pike.git / src / code / amd64.c

version» Context lines:

pike.git/src/code/amd64.c:1: + /* +  * Machine code generator for AMD64. +  */    -  + #include "operators.h" + #include "constants.h" + #include "object.h" + #include "builtin_functions.h" +  +  + /* This is defined on windows */ + #ifdef REG_NONE + #undef REG_NONE + #endif +  +  + /* Register encodings */ + enum amd64_reg {REG_RAX = 0, REG_RBX = 3, REG_RCX = 1, REG_RDX = 2, +  REG_R8 = 8, REG_R9 = 9, REG_10 = 10, REG_R11 = 11, +  REG_R12 = 12, REG_R13 = 13, REG_R14 = 14, REG_R15 = 15, REG_NONE = 4}; +  + #define CLEAR_REGS() do {} while (0) +  + #define PUSH_INT(X) ins_int((INT32)(X), (void (*)(char))add_to_program) +  + /* +  * Copies a 32 bit immidiate value to stack +  * 0xc7 = mov +  */ + #define MOV_VAL_TO_RELSTACK(VALUE, OFFSET) do { \ +  INT32 off_ = (OFFSET); \ +  add_to_program(0xc7); \ +  if (off_ < -128 || off_ > 127) { \ +  add_to_program (0x84); \ +  add_to_program (0x24); \ +  PUSH_INT (off_); \ +  } \ +  else if (off_) { \ +  add_to_program (0x44); \ +  add_to_program (0x24); \ +  add_to_program (off_); \ +  } \ +  else { \ +  add_to_program (0x04); \ +  add_to_program (0x24); \ +  } \ +  PUSH_INT(VALUE); \ + } while(0) \ +  +  +  + /* 0xe8 = call */ + #define CALL_RELATIVE(X) do{ \ +  struct program *p_=Pike_compiler->new_program; \ +  add_to_program(0xe8); \ +  add_to_program(0); \ +  add_to_program(0); \ +  add_to_program(0); \ +  add_to_program(0); \ +  add_to_relocations(p_->num_program-4); \ +  *(INT32 *)(p_->program + p_->num_program - 4)= \ +  ((INT32)(X)) - (INT32)(p_->program + p_->num_program); \ + }while(0) +  + static void update_arg1(INT32 value) { +  MOV_VAL_TO_RELSTACK(value, 0); + } +  + static void update_arg2(INT32 value) { +  MOV_VAL_TO_RELSTACK(value, 4); + } +  +  + static enum amd64_reg next_reg; + static enum amd64_reg sp_reg, fp_reg, mark_sp_reg; + ptrdiff_t amd64_prev_stored_pc; /* PROG_PC at the last point Pike_fp->pc was updated. */ +  +  + static void amd64_call_c_function(void *addr) { +  CALL_RELATIVE(addr); +  next_reg = REG_RAX; +  sp_reg = fp_reg = mark_sp_reg = REG_NONE; +  CLEAR_REGS(); + } +  +  + void amd64_update_pc(void) { +  INT32 tmp = PIKE_PC, disp; +  +  if (amd64_prev_stored_pc < 0) { +  enum amd64_reg tmp_reg = alloc_reg (1 << fp_reg); +  load_fp_reg (1 << tmp_reg); + #ifdef PIKE_DEBUG +  if (a_flag >= 60) +  fprintf (stderr, "pc %d update pc absolute\n", tmp); + #endif +  /* Store the negated pointer to make the relocation displacements +  * work in the right direction. */ +  MOV_VAL32_TO_REG (0, tmp_reg); +  add_to_relocations(PIKE_PC - 4); +  upd_pointer(PIKE_PC - 4, - (INT32) (tmp + Pike_compiler->new_program->program)); +  CHECK_VALID_REG (tmp_reg); +  add_to_program(0xf7); /* neg tmp_reg */ +  add_to_program(0xd8 | tmp_reg); +  MOV_REG_TO_RELADDR (tmp_reg, OFFSETOF (pike_frame, pc), fp_reg); +  DEALLOC_REG (tmp_reg); +  } +  else if ((disp = tmp - ia32_prev_stored_pc)) { + #ifdef PIKE_DEBUG +  if (a_flag >= 60) +  fprintf (stderr, "pc %d update pc relative: %d\n", tmp, disp); + #endif +  load_fp_reg (0); +  ADD_VAL_TO_RELADDR (disp, OFFSETOF (pike_frame, pc), fp_reg); +  } +  else { + #ifdef PIKE_DEBUG +  if (a_flag >= 60) +  fprintf (stderr, "pc %d update pc - already up-to-date\n", tmp); + #endif +  } +  amd64_prev_stored_pc = tmp; + } +  +  + static void maybe_update_pc(void) { +  static int last_prog_id=-1; +  static size_t last_num_linenumbers=-1; +  +  if( + #ifdef PIKE_DEBUG +  /* Update the pc more often for the sake of the opcode level trace. */ +  d_flag || + #endif +  (amd64_prev_stored_pc == -1) || +  last_prog_id != Pike_compiler->new_program->id || +  last_num_linenumbers != Pike_compiler->new_program->num_linenumbers +  ) { +  last_prog_id=Pike_compiler->new_program->id; +  last_num_linenumbers = Pike_compiler->new_program->num_linenumbers; +  UPDATE_PC(); +  } + } +  + void ins_f_byte(unsigned int b) { +  void *addr; +  b-=F_OFFSET; + #ifdef PIKE_DEBUG +  if(b>255) +  Pike_error("Instruction too big %d\n",b); + #endif +  maybe_update_pc(); +  addr=instrs[b].address; +  amd64_call_c_function(addr); + } +  + void ins_f_byte_with_arg(unsigned int a, unsigned INT32 b) { +  maybe_update_pc(); +  update_arg1(b); +  ins_f_byte(a); + } +  + void ins_f_byte_with_2_args(unsigned int a, unsigned INT32 b, unsigned INT32 c) { +  maybe_update_pc(); +  update_arg1(b); +  update_arg2(c); +  ins_f_byte(a); + } +    Newline at end of file added.