Branch: Tag:

2012-06-12

2012-06-12 21:16:15 by Per Hedbor <ph@opera.com>

Rewrote x86_64/AMD64 native code generation.

De-macrofied the generator to make it at least somewhat easier to
read, also attempted to make the opcode implementations easier to
understand (at least if you have a copy of the Intel Software
Developer's Manual in front of you.

There are known issues with some opcodes, mot all mov_* work with all
registers as arguments (due to the x86 instruction encoding for
register&7==[3,4])

Added a few more instructions, and changed some occurences of things
like 'mov $4, eax; mov eax,[ecx+off]' to 'mov $4,[ecx+off]'.

Added a simple branch/label system to make it somewhat easier to write
more complex opcodes.

Inlined or partially inlined some opcodes:

THIS_OBJECT, ASSIGN_LOCAL, ASSIGN_LOCAL_AND_POP, ASSIGN_GLOBAL,
ASSIGN_GLOBAL_AND_POP, POP_VALUE, SIZEOF_LOCAL, CONSTANT,
GLOBAL_LVALUE, LOCAL_LVALUE, BRANCH_IF[_NOT]_LOCAL and fixed INIT_FRAME.

Changed handling of 'check_threads_etc', it is now only called every
1024 branches (or, like normal, when functions are called).

Overall pure pike-code execution is about 20% faster.

49:   #define ARG6_REG REG_R9   #endif    +  + #define MAX_LABEL_USES 7 + struct label { +  int n_label_uses; +  ptrdiff_t offset[MAX_LABEL_USES]; + }; +  + static void label( struct label *l ) + { +  int i; +  for( i=0; i<l->n_label_uses; i++ ) +  { +  int dist = PIKE_PC - (l->offset[i] + 1); +  if( dist > 0x7f || dist < -0x80 ) +  Pike_fatal("Branch too far\n"); +  Pike_compiler->new_program->program[l->offset[i]] = dist; +  /* fprintf( stderr, "assigning label @%x[%02x >%02x< %02x] -> %d\n", */ +  /* l->offset[i], */ +  /* Pike_compiler->new_program->program[l->offset[i]-1], */ +  /* Pike_compiler->new_program->program[l->offset[i]], */ +  /* Pike_compiler->new_program->program[l->offset[i]+1], */ +  /* dist ); */ +  } +  l->n_label_uses = 0; + } +  + static void modrm( int mod, int r, int m ) + { +  add_to_program( ((mod<<6) | ((r&0x7)<<3) | (m&0x7)) ); + } +  + static void sib( int scale, int index, enum amd64_reg base ) + { +  add_to_program( (scale<<6) | ((index&0x7)<<3) | (base&0x7) ); + } +  + static void rex( int w, enum amd64_reg r, int x, enum amd64_reg b ) + { +  unsigned char res = 1<<6; +  /* bit 7, 5-4 == 0 */ +  if( w ) res |= 1<<3; +  if( r > 0x7 ) res |= 1<<2; +  if( x ) res |= 1<<1; +  if( b > 0x7 ) res |= 1<<0; +  if( res != (1<<6) ) +  add_to_program( res ); + } +  +  + static void ib( char x ) + { +  add_to_program( x ); + } +  + static void iw( short x ) + { +  add_to_program( x>>8 ); +  add_to_program( x ); + } +  + static void id( int x ) + { +  add_to_program( (x)&0xff ); +  add_to_program( (x>>8)&0xff ); +  add_to_program( (x>>16)&0xff ); +  add_to_program( (x>>24)&0xff ); + } +  + /* x86 opcodes */ + #define opcode(X) ib(X) +  + static void ret() + { +  opcode(0xc3); + } +  + static void push(enum amd64_reg reg ) + { +  if (reg & 0x08) add_to_program(0x41); +  add_to_program(0x50 + (reg & 0x07)); + } +  + static void pop(enum amd64_reg reg ) + { +  if (reg & 0x08) add_to_program(0x41); +  add_to_program(0x58 + (reg & 0x07)); + } +  + static void mov_reg_reg(enum amd64_reg from_reg, enum amd64_reg to_reg ) + { +  rex( 1, from_reg, 0, to_reg ); +  opcode( 0x89 ); +  modrm( 3, from_reg, to_reg ); + } +    #define PUSH_INT(X) ins_int((INT32)(X), (void (*)(char))add_to_program) -  + static void low_mov_mem_reg(enum amd64_reg from_reg, ptrdiff_t offset, enum amd64_reg to_reg) + { +  opcode( 0x8b );    - #define AMD64_RET() add_to_program(0xc3) +  /* Using r13 or rbp will trigger RIP relative +  if rex.W is set +  */ +  if( offset == 0 && from_reg != REG_R13 && from_reg != REG_RBP ) +  { +  modrm( 0, to_reg, from_reg ); +  } +  else +  { +  if( offset < 128 && offset >= -128 ) +  { +  modrm( 1, to_reg, from_reg ); +  ib( offset ); +  } +  else +  { +  modrm( 2, to_reg, from_reg ); +  id(offset); +  } +  } + }    - #define AMD64_NOP() add_to_program(0x90) + static void mov_mem_reg( enum amd64_reg from_reg, ptrdiff_t offset, enum amd64_reg to_reg ) + { +  rex( 1, to_reg, 0, from_reg ); +  low_mov_mem_reg( from_reg, offset, to_reg ); + }    - #define AMD64_PUSH(REG) do { \ -  enum amd64_reg reg__ = (REG); \ -  if (reg__ & 0x08) { \ -  add_to_program(0x41); \ -  } \ -  add_to_program(0x50 + (reg__ & 0x07)); \ -  } while(0) + static void mov_mem32_reg( enum amd64_reg from_reg, ptrdiff_t offset, enum amd64_reg to_reg ) + { +  rex( 0, to_reg, 0, from_reg ); +  low_mov_mem_reg( from_reg, offset, to_reg ); + }    - #define AMD64_POP(REG) do { \ -  enum amd64_reg reg__ = (REG); \ -  if (reg__ & 0x08) { \ -  add_to_program(0x41); \ -  } \ -  add_to_program(0x58 + (reg__ & 0x07)); \ -  } while(0) + static void and_reg_imm( enum amd64_reg reg, int imm32 ) + { +  rex( 1, 0, 0, reg );    - #define AMD64_MOV_REG(FROM_REG, TO_REG) do { \ -  enum amd64_reg from_reg__ = (FROM_REG); \ -  enum amd64_reg to_reg__ = (TO_REG); \ -  int rex__ = 0x48; \ -  if (from_reg__ & 0x08) { \ -  rex__ |= 0x04; \ -  from_reg__ &= 0x07; \ -  } \ -  if (to_reg__ & 0x08) { \ -  rex__ |= 0x01; \ -  to_reg__ &= 0x07; \ -  } \ -  add_to_program(rex__); \ -  add_to_program(0x89); \ -  add_to_program(0xc0|(from_reg__<<3)| \ -  to_reg__); \ -  } while (0) +  if( imm32 < -0x80 || imm32 > 0x7f ) +  { +  if( reg == REG_RAX ) +  { +  opcode( 0x25 ); // AND rax,imm32 +  id( imm32 ); +  } +  else +  { +  opcode( 0x81 ); // AND REG,imm32 +  modrm( 3,4, reg); +  id( imm32 ); +  } +  } +  else +  { +  add_to_program(0x83); // AND REG,imm8 +  modrm( 3, 4, reg ); +  ib( imm32 ); +  } + }    - #define AMD64_MOVE_RELADDR_TO_REG(FROM_REG, FROM_OFFSET, TO_REG) do { \ -  enum amd64_reg from_reg__ = (FROM_REG); \ -  enum amd64_reg to_reg__ = (TO_REG); \ -  int off32__ = (FROM_OFFSET); \ -  int rex__ = 0x48; \ -  if (from_reg__ & 0x08) { \ -  rex__ |= 0x01; \ -  from_reg__ &= 0x07; \ -  } \ -  if (to_reg__ & 0x08) { \ -  rex__ |= 0x04; \ -  to_reg__ &= 0x07; \ -  } \ -  add_to_program(rex__); \ -  add_to_program(0x8b); \ -  add_to_program(0x80|(to_reg__<<3)| from_reg__); \ -  PUSH_INT(off32__); \ -  } while(0) + static void mov_mem16_reg( enum amd64_reg from_reg, ptrdiff_t offset, enum amd64_reg to_reg ) + { +  // FIXME: Really implement.. +  mov_mem32_reg( from_reg, offset, to_reg ); +  and_reg_imm( to_reg, 0xffff ); + }    - #define AMD64_MOVE32_RELADDR_TO_REG(FROM_REG, FROM_OFFSET, TO_REG) do { \ -  enum amd64_reg from_reg__ = (FROM_REG); \ -  enum amd64_reg to_reg__ = (TO_REG); \ -  int off32__ = (FROM_OFFSET); \ -  int rex__ = 0x40; \ -  if (from_reg__ & 0x08) { \ -  rex__ |= 0x01; \ -  from_reg__ &= 0x07; \ -  } \ -  if (to_reg__ & 0x08) { \ -  rex__ |= 0x04; \ -  to_reg__ &= 0x07; \ -  } \ -  if (rex__ != 0x40) { \ -  add_to_program(rex__); \ -  } \ -  add_to_program(0x8b); \ -  add_to_program(0x80|(to_reg__<<3)| from_reg__); \ -  PUSH_INT(off32__); \ -  } while(0) + static void add_reg_imm( enum amd64_reg src, int imm32);    - #define AMD64_MOVE_REG_TO_RELADDR(FROM_REG, TO_REG, TO_OFFSET) do { \ -  enum amd64_reg from_reg__ = (FROM_REG); \ -  enum amd64_reg to_reg__ = (TO_REG); \ -  int off32__ = (TO_OFFSET); \ -  int rex__ = 0x48; \ -  if (from_reg__ & 0x08) { \ -  rex__ |= 0x04; \ -  from_reg__ &= 0x07; \ -  } \ -  if (to_reg__ & 0x08) { \ -  rex__ |= 0x01; \ -  to_reg__ &= 0x07; \ -  } \ -  add_to_program(rex__); \ -  add_to_program(0x89); \ -  if (!off32__ && (to_reg__ != REG_RBP)) { \ -  add_to_program((from_reg__<<3)| to_reg__); \ -  if (to_reg__ == REG_RSP) { \ -  add_to_program(0x24); \ -  } \ -  } else if ((-0x80 <= off32__) && (0x7f >= off32__)) { \ -  add_to_program(0x40|(from_reg__<<3)| to_reg__); \ -  if (to_reg__ == REG_RSP) { \ -  add_to_program(0x24); \ -  } \ -  add_to_program(off32__); \ -  } else { \ -  add_to_program(0x80|(from_reg__<<3)| to_reg__); \ -  PUSH_INT(off32__); \ -  } \ -  } while(0) + static void shl_reg_imm( enum amd64_reg from_reg, int shift ) + { +  rex( 1, from_reg, 0, 0 ); +  if( shift == 1 ) +  { +  opcode( 0xd1 ); // RCL +  modrm( 3, 2, from_reg ); +  } +  else +  { +  opcode( 0xc1 ); +  modrm( 3, 2, from_reg ); +  ib( shift ); +  } + }    - #define AMD64_SHL_IMM8(REG, IMM8) do { \ -  enum amd64_reg reg__ = (REG); \ -  int imm8__ = (IMM8); \ -  if (reg__ & 0x08) { \ -  add_to_program(0x49); \ -  reg__ &= 0x07; \ -  } else { \ -  add_to_program(0x48); \ -  } \ -  if (imm8__ == 1) { \ -  add_to_program(0xd1); \ -  add_to_program(0xe0|reg__); \ -  } else { \ -  add_to_program(0xc1); \ -  add_to_program(0xe0|reg__); \ -  add_to_program(imm8__); \ -  } \ -  } while(0) + static void xor_reg_reg( enum amd64_reg reg1, enum amd64_reg reg2 ) + { +  rex(1,reg1,0,reg2); +  opcode( 0x31 ); +  modrm(3,reg1,reg2); + }    - #define AMD64_AND_IMM32(REG, IMM32) do { \ -  enum amd64_reg reg__ = (REG); \ -  int imm32__ = (IMM32); \ -  if (reg__ & 0x08) { \ -  add_to_program(0x49); \ -  reg__ &= 0x07; \ -  } else { \ -  add_to_program(0x48); \ -  } \ -  if ((imm32__ >= -0x80) && (imm32__ <= 0x7f)) { \ -  add_to_program(0x83); \ -  add_to_program(0xe0|reg__); \ -  add_to_program(imm32__); \ -  } else { \ -  add_to_program(0x81); \ -  add_to_program(0xe0|reg__); \ -  PUSH_INT(imm32__); \ -  } \ -  } while(0) + static void clear_reg( enum amd64_reg reg ) + { +  xor_reg_reg( reg, reg ); + }    - #define AMD64_ADD_IMM32(REG, IMM32) do { \ -  enum amd64_reg reg__ = (REG); \ -  int imm32__ = (IMM32); \ -  if (reg__ & 0x08) { \ -  add_to_program(0x49); \ -  reg__ &= 0x07; \ -  } else { \ -  add_to_program(0x48); \ -  } \ -  if ((imm32__ >= -0x80) && (imm32__ <= 0x7f)) { \ -  add_to_program(0x83); \ -  add_to_program(0xc0|reg__); \ -  add_to_program(imm32__); \ -  } else { \ -  add_to_program(0x81); \ -  add_to_program(0xc0|reg__); \ -  PUSH_INT(imm32__); \ -  } \ -  } while(0) + static void mov_imm_reg( long imm, enum amd64_reg reg ) + { +  if( (imm > 0x7fffffffLL) || (imm < -0x80000000LL) ) +  { +  rex(1,0,0,reg); +  opcode(0xb8 | (reg&0x7)); /* mov imm64 -> reg64 */ +  id( (imm & 0xffffffffLL) ); +  id( ((imm >> 32)&0xffffffffLL) ); +  } +  else +  { +  rex(1,0,0,reg); +  opcode( 0xc7 ); /* mov imm32 -> reg/m 64, SE*/ +  modrm( 3,0,reg ); +  id( (int)imm ); +  } + }    - #define AMD64_SUB_IMM32(REG, IMM32) do { \ -  enum amd64_reg reg__ = (REG); \ -  int imm32__ = (IMM32); \ -  if (reg__ & 0x08) { \ -  add_to_program(0x49); \ -  reg__ &= 0x07; \ -  } else { \ -  add_to_program(0x48); \ -  } \ -  add_to_program(0x83); \ -  if ((imm32__ >= -0x80) && (imm32__ <= 0x7f)) { \ -  add_to_program(0xe8|reg__); \ -  add_to_program(imm32__); \ -  } else { \ -  Pike_fatal("Not supported yet.\n"); \ -  PUSH_INT(imm32__); \ -  } \ -  } while(0) + static void mov_reg_mem( enum amd64_reg from_reg, enum amd64_reg to_reg, ptrdiff_t offset ) + { +  rex(1, from_reg, 0, to_reg ); +  opcode( 0x89 );    - #define AMD64_TEST_REG(REG) do { \ -  enum amd64_reg reg__ = (REG); \ -  if (reg__ & 0x08) { \ -  add_to_program(0x4d); \ -  reg__ &= 0x07; \ -  } else { \ -  add_to_program(0x48); \ -  } \ -  add_to_program(0x85); \ -  add_to_program(0xc0|(reg__ <<3)|reg__); \ -  } while(0) +  if( !offset && ((to_reg&7) != REG_RBP) ) +  { +  modrm( 0, from_reg, to_reg ); +  if( (to_reg&7) == REG_RSP) +  sib(0, REG_RSP, REG_RSP ); +  } +  else +  { +  if( offset < 128 && offset >= -128 ) +  { +  modrm( 1, from_reg, to_reg ); +  if( (to_reg&7) == REG_RSP) +  sib(0, REG_RSP, REG_RSP ); +  ib( offset ); +  } +  else +  { +  modrm( 2, from_reg, to_reg ); +  if( (to_reg&7) == REG_RSP ) +  sib(0, REG_RSP, REG_RSP ); +  id( offset ); +  } +  } + }    - #define AMD64_CMP_REG_IMM32(REG, IMM32) do { \ -  enum amd64_reg reg__ = (REG); \ -  int imm32__ = (IMM32); \ -  if (reg__ & 0x08) { \ -  add_to_program(0x49); \ -  reg__ &= 0x07; \ -  } else { \ -  add_to_program(0x48); \ -  } \ -  add_to_program(0x83); \ -  if ((imm32__ >= -0x80) && (imm32__ <= 0x7f)) { \ -  add_to_program(0xf8|reg__); \ -  add_to_program(imm32__); \ -  } else { \ -  Pike_fatal("Not supported yet.\n"); \ -  PUSH_INT(imm32__); \ -  } \ -  } while(0) + static void mov_imm_mem( long imm, enum amd64_reg to_reg, ptrdiff_t offset ) + { +  if( imm >= -0x80000000LL && imm <= 0x7fffffffLL ) +  { +  rex( 1, 0, 0, to_reg ); +  opcode( 0xc7 ); /* mov imm32 -> r/m64 (sign extend)*/ +  /* This does not work for rg&7 == 4 or 5. */ +  if( !offset && (to_reg&7) != 4 && (to_reg&7) != 5 ) +  { +  modrm( 0, 0, to_reg ); +  } +  else if( offset >= -128 && offset < 128 ) +  { +  modrm( 1, 0, to_reg ); +  ib( offset ); +  } +  else +  { +  modrm( 2, 0, to_reg ); +  id( offset ); +  } +  id( imm ); +  } +  else +  { +  if( to_reg == REG_RAX ) +  Pike_fatal( "Clobbered TMP REG_RAX reg\n"); +  mov_imm_reg( imm, REG_RAX ); +  mov_reg_mem( REG_RAX, to_reg, offset ); +  } + }    - #define AMD64_CMP_REG(REG1, REG2) do { \ -  enum amd64_reg reg1__ = (REG1); \ -  enum amd64_reg reg2__ = (REG2); \ -  int rex = 0x48; \ -  if (reg1__ & 0x08) { \ -  rex |= 0x04; \ -  reg1__ &= 0x07; \ -  } \ -  if (reg2__ & 0x08) { \ -  rex |= 0x01; \ -  reg2__ &= 0x07; \ -  } \ -  add_to_program(rex); \ -  add_to_program(0x39); \ -  add_to_program(0xc0|(reg1__<<3)|reg2__); \ -  } while(0) +     - #define AMD64_JUMP_REG(REG) do { \ -  enum amd64_reg reg__ = (REG); \ -  if (reg__ & 0x08) { \ -  add_to_program(0x41); \ -  reg__ &= 0x07; \ -  } \ -  add_to_program(0xff); \ -  add_to_program(0xe0|reg__); \ -  } while(0) +     - #define AMD64_CALL_REL32(REG, REL32) do { \ -  AMD64_ADD_REG_IMM32(REG, REL32, REG_RAX); \ -  add_to_program(0xff); \ -  add_to_program(0xd0); \ -  } while(0) + static void mov_reg_mem32( enum amd64_reg from_reg, enum amd64_reg to_reg, ptrdiff_t offset ) + { +  rex(0, from_reg, 0, to_reg ); +  opcode( 0x89 );    - /* CALL *addr */ - #define CALL_ABSOLUTE(X) do { \ -  size_t addr__ = (size_t)(void *)(X); \ -  if (addr__ & ~0x7fffffffLL) { \ -  /* Apple in their wisdom has the text \ -  * segment in the second 4GB block... \ -  * \ -  * Fortunately function entry points \ -  * are at least 32-bit aligned. \ -  */ \ -  if (!(addr__ & ~0x3fffffff8LL)) { \ -  AMD64_LOAD_IMM32(REG_RAX, addr__>>3); \ -  AMD64_SHL_IMM8(REG_RAX, 3); \ -  } else { \ -  /* Catch all. */ \ -  AMD64_LOAD_IMM(REG_RAX, addr__); \ -  } \ -  } else { \ -  /* Low 31-bit block. \ -  * Linux, Solaris, etc... */ \ -  AMD64_LOAD_IMM32(REG_RAX, addr__); \ -  } \ -  add_to_program(0xff); \ -  add_to_program(0xd0); \ -  } while(0) +  if( !offset && ((to_reg&7) != REG_RBP) ) +  { +  modrm( 0, from_reg, to_reg ); +  if( (to_reg&7) == REG_RSP) +  sib(0, REG_RSP, REG_RSP ); +  } +  else +  { +  if( offset < 128 && offset >= -128 ) +  { +  modrm( 1, from_reg, to_reg ); +  if( (to_reg&7) == REG_RSP) +  sib(0, REG_RSP, REG_RSP ); +  ib( offset ); +  } +  else +  { +  modrm( 2, from_reg, to_reg ); +  if( (to_reg&7) == REG_RSP ) +  sib(0, REG_RSP, REG_RSP ); +  id( offset ); +  } +  } + }    - #define AMD64_CLEAR_REG(REG) do { \ -  enum amd64_reg creg__ = (REG); \ -  if (creg__ & 0x08) { \ -  add_to_program(0x4d); \ -  creg__ &= 0x07; \ -  } else { \ -  add_to_program(0x48); \ -  } \ -  add_to_program(0x31); \ -  add_to_program(0xc0|(creg__<<3)|creg__); \ -  } while(0) +     - #define AMD64_ADD_REG_IMM32(FROM_REG, IMM32, TO_REG) do { \ -  enum amd64_reg from_reg__ = (FROM_REG); \ -  enum amd64_reg to_reg__ = (TO_REG); \ -  int imm32__ = (IMM32); \ -  if (!imm32__) { \ -  if (from_reg__ != to_reg__) { \ -  AMD64_MOV_REG(from_reg__, to_reg__); \ -  } \ -  } else { \ -  int rex = 0x48; \ -  if (from_reg__ & 0x08) { \ -  rex |= 0x01; \ -  from_reg__ &= 0x07; \ -  } \ -  if (to_reg__ & 0x08) { \ -  rex |= 0x04; \ -  to_reg__ &= 0x07; \ -  } \ -  add_to_program(rex); \ -  add_to_program(0x8d); \ -  if ((-0x80 <= imm32__) && (0x7f >= imm32__)) { \ -  add_to_program(0x40|(to_reg__<<3)|from_reg__); \ -  add_to_program(imm32__); \ -  } else { \ -  add_to_program(0x80|(to_reg__<<3)|from_reg__); \ -  PUSH_INT(imm32__); \ -  } \ -  } \ -  } while(0) + static void mov_imm_mem32( int imm, enum amd64_reg to_reg, ptrdiff_t offset ) + { +  rex( 0, 0, 0, to_reg ); +  opcode( 0xc7 ); /* mov imm32 -> r/m32 (sign extend)*/ +  /* This does not work for rg&7 == 4 or 5. */ +  if( !offset && (to_reg&7) != 4 && (to_reg&7) != 5 ) +  { +  modrm( 0, 0, to_reg ); +  } +  else if( offset >= -128 && offset < 128 ) +  { +  modrm( 1, 0, to_reg ); +  ib( offset ); +  } +  else +  { +  modrm( 2, 0, to_reg ); +  id( offset ); +  } +  id( imm ); + }    - #define AMD64_LOAD_RIP32(RIP32, REG) do { \ -  enum amd64_reg reg__ = (REG); \ -  int rip32__ = (RIP32); \ -  if (reg__ & 0x08) { \ -  add_to_program(0x4c); \ -  reg__ &= 0x07; \ -  } else { \ -  add_to_program(0x48); \ -  } \ -  add_to_program(0x8d); \ -  add_to_program(0x05|(reg__<<3)); \ -  PUSH_INT(rip32__); \ -  } while(0) + static void add_reg_imm( enum amd64_reg reg, int imm32 ) + { +  if( !imm32 ) return;    - #define AMD64_MOVE_RIP32_TO_REG(RIP32, REG) do { \ -  enum amd64_reg reg__ = (REG); \ -  int rip32__ = (RIP32); \ -  if (reg__ & 0x08) { \ -  add_to_program(0x4c); \ -  reg__ &= 0x07; \ -  } else { \ -  add_to_program(0x48); \ -  } \ -  add_to_program(0x8b); \ -  add_to_program(0x05|(reg__<<3)); \ -  PUSH_INT(rip32__); \ -  } while(0) +  rex( 1, 0, 0, reg );    - #define AMD64_MOVE32_RIP32_TO_REG(RIP32, REG) do { \ -  enum amd64_reg reg__ = (REG); \ -  int rip32__ = (RIP32); \ -  if (reg__ & 0x08) { \ -  add_to_program(0x44); \ -  reg__ &= 0x07; \ -  } \ -  add_to_program(0x8b); \ -  add_to_program(0x05|(reg__<<3)); \ -  PUSH_INT(rip32__); \ -  } while(0) +  if( imm32 < -0x80 || imm32 > 0x7f ) +  { +  if( reg == REG_RAX ) +  { +  opcode( 0x05 ); // ADD rax,imm32 +  id( imm32 ); +  } +  else +  { +  opcode( 0x81 ); // ADD REG,imm32 +  modrm( 3, 0, reg); +  id( imm32 ); +  } +  } +  else +  { +  add_to_program(0x83); // ADD REG,imm8 +  modrm( 3, 0, reg ); +  ib( imm32 ); +  } + }    - #define AMD64_LOAD_IMM32(REG, IMM32) do { \ -  enum amd64_reg reg__ = (REG); \ -  int imm32__ = (IMM32); \ -  if (!imm32__) { \ -  AMD64_CLEAR_REG(reg__); \ -  } else { \ -  if (reg__ & 0x08) { \ -  add_to_program(0x49); \ -  reg__ &= 0x07; \ -  } else { \ -  add_to_program(0x48); \ -  } \ -  add_to_program(0xc7); \ -  add_to_program(0xc0|reg__); \ -  PUSH_INT(imm32__); \ -  } \ -  } while(0) + static void add_mem32_imm( enum amd64_reg reg, int offset, int imm32 ) + { +  int r2 = imm32 == -1 ? 1 : 0; +  int large = 0; +  if( !imm32 ) return; +  rex( 0, 0, 0, reg );    - #define AMD64_LOAD_IMM(REG, IMM) do { \ -  enum amd64_reg reg64__ = (REG); \ -  INT64 imm__ = (IMM); \ -  if ((-0x80000000LL <= imm__) && \ -  (0x7fffffffLL >= imm__)) { \ -  AMD64_LOAD_IMM32(reg64__, imm__); \ -  } else { \ -  if (imm__ & 0x80000000LL) { \ -  /* 32-bit negative. */ \ -  AMD64_LOAD_IMM32(reg64__, (imm__>>32) + 1); \ -  } else { \ -  AMD64_LOAD_IMM32(reg64__, (imm__>>32)); \ -  } \ -  AMD64_SHL_IMM8(reg64__, 32); \ -  AMD64_ADD_REG_IMM32(reg64__, imm__, reg64__); \ -  } \ -  } while(0) +  if( r2 ) imm32 = -imm32;    - #define AMD64_ADD_VAL_TO_RELADDR(VAL, OFFSET, REG) do { \ -  INT32 val_ = (VAL); \ -  INT32 off_ = (OFFSET); \ -  enum amd64_reg reg_ = (REG); \ -  if (val_) { \ -  if (reg_ & 0x08) { \ -  add_to_program(0x41); \ -  reg_ &= 0x07; \ -  } \ -  if (val_ == 1) \ -  /* incl offset(%reg) */ \ -  add_to_program (0xff); /* Increment r/m32 */ \ -  else if (val_ == -1) { \ -  /* decl offset(%reg) */ \ -  add_to_program (0xff); /* Decrement r/m32 */ \ -  reg_ |= 1 << 3; \ -  } \ -  else if (-128 <= val_ && val_ <= 127) \ -  /* addl $val,offset(%reg) */ \ -  add_to_program (0x83); /* Add sign-extended imm8 to r/m32. */ \ -  else \ -  /* addl $val,offset(%reg) */ \ -  add_to_program (0x81); /* Add imm32 to r/m32. */ \ -  if (off_ < -128 || off_ > 127) { \ -  add_to_program (0x80 | reg_); \ -  PUSH_INT (off_); \ -  } \ -  else if (off_) { \ -  add_to_program (0x40 | reg_); \ -  add_to_program (off_); \ -  } \ -  else \ -  add_to_program (reg_); \ -  if (val_ != 1 && val_ != -1) { \ -  if (-128 <= val_ && val_ <= 127) \ -  add_to_program (val_); \ -  else \ -  PUSH_INT (val_); \ -  } \ -  } \ -  } while (0) +  if( imm32 == 1 ) +  opcode( 0xff ); // INCL(DECL) r/m32 +  else if( imm32 >= -128 && imm32 < 128 ) +  opcode( 0x83 ); // ADD imm8,r/m32 +  else +  { +  opcode( 0x81 ); // ADD imm32,r/m32 +  large = 1; +  } +  if( !offset ) +  { +  modrm( 0, r2, reg ); +  } +  else +  if( offset < -128 || offset > 127 ) +  { +  modrm( 2, r2, reg ); +  id( offset ); +  } +  else +  { +  modrm( 1, r2, reg ); +  ib( offset ); +  } +  if( imm32 != 1 ) +  { +  if( large ) +  id( imm32 ); +  else +  ib( imm32 ); +  } + }    - #define AMD64_JMP(SKIP) do {\ -  int skip__ = (SKIP); \ -  if ((skip__ >= -0x80) && (skip__ <= 0x7f)) { \ -  add_to_program(0xeb); \ -  add_to_program(skip__); \ -  } else { \ -  Pike_fatal("Not supported yet.\n"); \ -  } \ -  } while(0) + static void sub_mem32_imm( enum amd64_reg reg, int offset, int imm32 ) + { +  add_mem32_imm( reg, offset, -imm32 ); + }    - #define AMD64_JNE(SKIP) do {\ -  int skip__ = (SKIP); \ -  if ((skip__ >= -0x80) && (skip__ <= 0x7f)) { \ -  add_to_program(0x75); \ -  add_to_program(skip__); \ -  } else { \ -  Pike_fatal("Not supported yet.\n"); \ -  } \ -  } while(0) + static void add_mem_imm( enum amd64_reg reg, int offset, int imm32 ) + { +  int r2 = imm32 == -1 ? 1 : 0; +  int large = 0; +  if( !imm32 ) return; +  rex( 1, 0, 0, reg );    - #define AMD64_JE(SKIP) do {\ -  int skip__ = (SKIP); \ -  if ((skip__ >= -0x80) && (skip__ <= 0x7f)) { \ -  add_to_program(0x74); \ -  add_to_program(skip__); \ -  } else { \ -  Pike_fatal("Not supported yet.\n"); \ -  } \ -  } while(0) +  if( imm32 == 1 || imm32 == -1 ) +  opcode( 0xff ); // INCL r/m32 +  else if( imm32 >= -128 && imm32 < 128 ) +  opcode( 0x83 ); // ADD imm8,r/m32 +  else +  { +  opcode( 0x81 ); // ADD imm32,r/m32 +  large = 1; +  }    - #define AMD64_JG(SKIP) do {\ -  int skip__ = (SKIP); \ -  if ((skip__ >= -0x80) && (skip__ <= 0x7f)) { \ -  add_to_program(0x7f); \ -  add_to_program(skip__); \ -  } else { \ -  Pike_fatal("Not supported yet.\n"); \ -  } \ -  } while(0) +  if( !offset ) +  { +  modrm( 0, r2, reg ); +  } +  else if( offset < -128 || offset > 127 ) +  { +  modrm( 2, r2, reg ); +  id( offset ); +  } +  else +  { +  modrm( 1, r2, reg ); +  ib( offset ); +  }    -  +  if( large ) +  id( imm32 ); +  else +  ib( imm32 ); + } +  + static void sub_reg_imm( enum amd64_reg reg, int imm32 ) + { + #if 0 +  return add_reg_imm( reg, -imm32 ); + #else +  if( !imm32 ) return; +  +  rex( 1, 0, 0, reg ); +  +  if( imm32 < -0x80 || imm32 > 0x7f ) +  { +  if( reg == REG_RAX ) +  { +  opcode( 0x2d ); // SUB rax,imm32 +  id( imm32 ); +  } +  else +  { +  opcode( 0x81 ); // SUB REG,imm32 +  modrm( 3, 5, reg); +  id( imm32 ); +  } +  } +  else +  { +  opcode(0x83); // SUB REG,imm8 +  modrm( 3, 5, reg ); +  ib( imm32 ); +  } + #endif + } +  + static void test_reg_reg( enum amd64_reg reg1, enum amd64_reg reg2 ) + { +  rex(1,reg1,0,reg2); +  opcode(0x85); +  modrm(3, reg1, reg2 ); + } +  + static void test_reg( enum amd64_reg reg1 ) + { +  test_reg_reg( reg1, reg1 ); + } +  + static void cmp_reg_imm( enum amd64_reg reg, int imm32 ) + { +  rex(1, 0, 0, reg); +  if( imm32 > 0x7f || imm32 < -0x80 ) +  { +  if( reg == REG_RAX ) +  { +  opcode( 0x3d ); +  id( imm32 ); +  } +  else +  { +  opcode( 0x81 ); +  modrm(3,7,reg); +  id( imm32 ); +  } +  } +  else +  { +  opcode( 0x83 ); +  modrm( 3,7,reg); +  ib( imm32 ); +  } + } +  + static void cmp_reg_reg( enum amd64_reg reg1, enum amd64_reg reg2 ) + { +  rex(1, reg1, 0, reg2); +  opcode( 0x39 ); +  modrm( 3, reg1, reg2 ); + } +  + static int jmp_rel_imm32( int rel ) + { +  int res; +  opcode( 0xe9 ); +  res = PIKE_PC; +  id( rel ); +  return res; + } +  + static void jmp_rel_imm( int rel ) + { +  if(rel >= -0x80 && rel <= 0x7f ) +  { +  opcode( 0xeb ); +  ib( rel ); +  return; +  } +  jmp_rel_imm32( rel ); + } +  + static void jmp_reg( enum amd64_reg reg ) + { +  rex(0,reg,0,0); +  opcode( 0xff ); +  modrm( 3, 4, reg ); + } +  + static void call_reg( enum amd64_reg reg ) + { +  rex(0,reg,0,0); +  opcode( 0xff ); +  modrm( 3, 2, reg ); + } +  + static void call_imm( void *ptr ) + { +  size_t addr = (size_t)ptr; +  if( (addr & ~0x7fffffffLL) && !(addr & ~0x3fffffff8LL) ) +  { +  mov_imm_reg( addr>>3, REG_RAX); +  shl_reg_imm( REG_RAX, 3 ); +  } +  else +  { +  mov_imm_reg(addr, REG_RAX ); +  } +  call_reg( REG_RAX ); + } +  +  + /* dst = src + imm32 (LEA, does not set flags!) */ + static void add_reg_imm_reg( enum amd64_reg src, long imm32, enum amd64_reg dst ) + { +  if( imm32 > 0x7fffffffLL || +  imm32 <-0x80000000LL) +  Pike_fatal("LEA [reg+imm] > 32bit Not supported\n"); +  +  if( src == dst ) +  { +  if( !imm32 ) return; +  add_reg_imm( src, imm32 ); +  } +  else +  { +  if( !imm32 ) +  { +  mov_reg_reg( src, dst ); +  return; +  } +  rex(1,dst,0,src); +  opcode( 0x8d ); /* LEA r64,m */ +  if( imm32 <= 0xf7 && imm32 >= -0x80 ) +  { +  modrm(1,dst,src); +  ib( imm32 ); +  } +  else +  { +  modrm(2,dst,src); +  id( imm32 ); +  } +  } + } +  + /* load code adress + imm to reg, always 32bit offset */ + static void mov_rip_imm_reg( int imm, enum amd64_reg reg ) + { +  imm -= 7; // The size of this instruction +  +  rex( 1, reg, 0, 0 ); +  opcode( 0x8d ); // LEA +  modrm( 0, reg, 5 ); +  id( imm ); + } +  + static void add_imm_mem( int imm32, enum amd64_reg reg, int offset ) + { +  int r2 = (imm32 == -1) ? 1 : 0; +  int large = 0; +  +  /* OPCODE */ +  rex( 1, 0, 0, reg ); +  if( imm32 == 1 || imm32 == -1 ) +  opcode( 0xff ); // INCL(decl) r/m32 +  else if( -128 <= imm32 && 128 > imm32 ) +  opcode( 0x83 ); // ADD imm8,r/m32 +  else +  { +  opcode( 0x81 ); // ADD imm32,r/m32 +  large = 1; +  } +  +  /* OFFSET */ +  if( offset < -128 || offset > 127 ) +  { +  modrm( 2, r2, reg ); +  id( offset ); +  } +  else if( offset ) +  { +  modrm( 1, r2, reg ); +  ib( offset ); +  } +  else +  { +  modrm( 0, r2, reg ); +  } +  +  /* VALUE */ +  if( imm32 != 1 && !r2 ) +  { +  if( large ) +  id( imm32 ); +  else +  ib( imm32 ); +  } + } +  +  + static void jump_rel8( struct label *res, unsigned char op ) + { +  opcode( op ); +  +  if( res->n_label_uses >= MAX_LABEL_USES ) +  Pike_fatal( "Label used too many times\n" ); +  res->offset[res->n_label_uses] = PIKE_PC; +  res->n_label_uses++; +  +  ib(0); + } +  + static int jnz_imm_rel32( int rel ) + { +  int res; +  opcode( 0xf ); +  opcode( 0x85 ); +  res = PIKE_PC; +  id( rel ); +  return res; + } +  + static int jz_imm_rel32( int rel ) + { +  int res; +  opcode( 0xf ); +  opcode( 0x84 ); +  res = PIKE_PC; +  id( rel ); +  return res; + } +  + #define jne(X) jnz(X) + #define je(X) jz(X) + static void jmp( struct label *l ) { return jump_rel8( l, 0xeb ); } + static void jnz( struct label *l ) { return jump_rel8( l, 0x75 ); } + static void jz( struct label *l ) { return jump_rel8( l, 0x74 ); } + static void jg( struct label *l ) { return jump_rel8( l, 0x7f ); } + static void jo( struct label *l ) { return jump_rel8( l, 0x70 ); } +  +  + #define LABELS() struct label label_A, label_B, label_C;label_A.n_label_uses = 0;label_B.n_label_uses = 0;label_C.n_label_uses = 0; + #define LABEL_A label(&label_A) + #define LABEL_B label(&label_B) + #define LABEL_C label(&label_C) +    /* Machine code entry prologue.    *    * On entry:
540:   void amd64_ins_entry(void)   {    /* Push all registers that the ABI requires to be preserved. */ -  AMD64_PUSH(REG_RBP); -  AMD64_MOV_REG(REG_RSP, REG_RBP); -  AMD64_PUSH(REG_R15); -  AMD64_PUSH(REG_R14); -  AMD64_PUSH(REG_R13); -  AMD64_PUSH(REG_R12); -  AMD64_PUSH(REG_RBX); -  AMD64_SUB_IMM32(REG_RSP, 8); /* Align on 16 bytes. */ +  push(REG_RBP); +  mov_reg_reg(REG_RSP, REG_RBP); +  push(REG_R15); +  push(REG_R14); +  push(REG_R13); +  push(REG_R12); +  push(REG_RBX); +  sub_reg_imm(REG_RSP, 8); /* Align on 16 bytes. */    -  AMD64_MOV_REG(ARG1_REG, Pike_interpreter_reg); +  mov_reg_reg(ARG1_REG, Pike_interpreter_reg);       amd64_flush_code_generator_state();   }    - #define ALLOC_REG(REG) do {} while (0) - #define DEALLOC_REG(REG) do {} while (0) - #define CLEAR_REGS() do {} while (0) -  - /* -  * 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) \ -  +    static enum amd64_reg next_reg = 0;   static enum amd64_reg sp_reg = 0, fp_reg = 0, mark_sp_reg = 0; - static int dirty_regs = 0; + static int dirty_regs = 0, ret_for_func = 0;   ptrdiff_t amd64_prev_stored_pc = -1; /* PROG_PC at the last point Pike_fp->pc was updated. */      void amd64_flush_code_generator_state(void)
594:    fp_reg = 0;    mark_sp_reg = 0;    dirty_regs = 0; +  ret_for_func = 0;    amd64_prev_stored_pc = -1;   }   
601:   {    /* NB: PIKE_FP_REG is currently never dirty. */    if (dirty_regs & (1 << PIKE_SP_REG)) { -  AMD64_MOVE_REG_TO_RELADDR(PIKE_SP_REG, Pike_interpreter_reg, +  mov_reg_mem(PIKE_SP_REG, Pike_interpreter_reg,    OFFSETOF(Pike_interpreter_struct, stack_pointer));    dirty_regs &= ~(1 << PIKE_SP_REG);    }    if (dirty_regs & (1 << PIKE_MARK_SP_REG)) { -  AMD64_MOVE_REG_TO_RELADDR(PIKE_MARK_SP_REG, Pike_interpreter_reg, +  mov_reg_mem(PIKE_MARK_SP_REG, Pike_interpreter_reg,    OFFSETOF(Pike_interpreter_struct, mark_stack_pointer));    dirty_regs &= ~(1 << PIKE_MARK_SP_REG);    }   }    - static enum amd64_reg alloc_reg (int avoid_regs) - { -  enum amd64_reg reg; -  int used_regs = (avoid_regs | REG_RESERVED) & REG_BITMASK; +     -  avoid_regs |= REG_RESERVED; -  -  if (used_regs != REG_BITMASK) { -  /* There's a free register. */ -  -  for (reg = next_reg; (1 << reg) & used_regs;) { -  reg = (reg + 1); -  if (reg >= REG_MAX) reg = 0; - #ifdef PIKE_DEBUG -  if (reg == next_reg) Pike_fatal ("Failed to find a free register.\n"); - #endif -  } -  } -  -  else { -  /* Choose a register with simple round robin. If we get more -  * things to hold than there are registers then this should -  * probably be replaced with an LRU strategy. */ -  -  for (reg = next_reg; (1 << reg) & avoid_regs;) { -  reg = (reg + 1); -  if (reg >= REG_MAX) reg = 0; - #ifdef PIKE_DEBUG -  if (reg == next_reg) Pike_fatal ("Failed to find a non-excluded register.\n"); - #endif -  } -  } -  - #ifdef REGISTER_DEBUG -  if ((1 << reg) & alloc_regs) Pike_fatal ("Clobbering allocated register.\n"); -  alloc_regs &= avoid_regs; - #endif -  ALLOC_REG (reg); -  -  next_reg = reg+1; -  if (next_reg >= REG_MAX) next_reg = 0; -  -  return reg; - } -  +    /* NB: We load Pike_fp et al into registers that    * are persistent across function calls.    */   void amd64_load_fp_reg(void)   {    if (!fp_reg) { -  AMD64_MOVE_RELADDR_TO_REG(Pike_interpreter_reg, +  mov_mem_reg(Pike_interpreter_reg,    OFFSETOF(Pike_interpreter_struct, frame_pointer),    PIKE_FP_REG);    fp_reg = PIKE_FP_REG;
673:   void amd64_load_sp_reg(void)   {    if (!sp_reg) { -  AMD64_MOVE_RELADDR_TO_REG(Pike_interpreter_reg, +  mov_mem_reg(Pike_interpreter_reg,    OFFSETOF(Pike_interpreter_struct, stack_pointer),    PIKE_SP_REG);    sp_reg = PIKE_SP_REG;
683:   void amd64_load_mark_sp_reg(void)   {    if (!mark_sp_reg) { -  AMD64_MOVE_RELADDR_TO_REG(Pike_interpreter_reg, +  mov_mem_reg(Pike_interpreter_reg,    OFFSETOF(Pike_interpreter_struct, mark_stack_pointer),    PIKE_MARK_SP_REG);    mark_sp_reg = PIKE_MARK_SP_REG;    }   }    -  -  +    static void update_arg1(INT32 value)   { -  AMD64_LOAD_IMM32(ARG1_REG, value); +  mov_imm_reg(value, ARG1_REG);    /* FIXME: Alloc stack space on NT. */   }      static void update_arg2(INT32 value)   { -  AMD64_LOAD_IMM32(ARG2_REG, value); +  mov_imm_reg(value, ARG2_REG);    /* FIXME: Alloc stack space on NT. */   }    -  + static void amd64_add_sp( int num ) + { +  amd64_load_sp_reg(); +  if( num > 0 ) +  add_reg_imm( sp_reg, sizeof(struct svalue)*num); +  else +  sub_reg_imm( sp_reg, sizeof(struct svalue)*-num); +  dirty_regs |= 1 << PIKE_SP_REG; +  flush_dirty_regs(); /* FIXME: Why is this needed? */ + } +  + static void amd64_add_mark_sp( int num ) + { +  amd64_load_mark_sp_reg(); +  add_reg_imm( mark_sp_reg, sizeof(struct svalue*)*num); +  dirty_regs |= 1 << PIKE_MARK_SP_REG; + #if 0 +  flush_dirty_regs(); /* FIXME: Why is this needed? */ + #endif + } +    /* Note: Uses RAX and RCX internally. reg MUST not be REG_RAX. */   static void amd64_push_svaluep(int reg)   { -  INT32 skip; +  LABELS(); +     amd64_load_sp_reg(); -  AMD64_MOVE_RELADDR_TO_REG(reg, OFFSETOF(svalue, type), REG_RAX); -  AMD64_MOVE_RELADDR_TO_REG(reg, OFFSETOF(svalue, u.refs), REG_RCX); -  AMD64_MOVE_REG_TO_RELADDR(REG_RAX, sp_reg, OFFSETOF(svalue, type)); -  AMD64_AND_IMM32(REG_RAX, 0x1f); -  AMD64_MOVE_REG_TO_RELADDR(REG_RCX, sp_reg, OFFSETOF(svalue, u.refs)); -  AMD64_CMP_REG_IMM32(REG_RAX, MAX_REF_TYPE); -  AMD64_JG(0); -  skip = PIKE_PC; -  AMD64_ADD_VAL_TO_RELADDR(1, OFFSETOF(pike_string, refs), REG_RCX); -  Pike_compiler->new_program->program[skip-1] = ((INT32)PIKE_PC) - skip; -  AMD64_ADD_IMM32(sp_reg, sizeof(struct svalue)); -  dirty_regs |= 1 << sp_reg; -  /* FIXME: Deferred writing of Pike_sp doen't seem to work reliably yet. */ -  if (dirty_regs & (1 << PIKE_SP_REG)) { -  AMD64_MOVE_REG_TO_RELADDR(PIKE_SP_REG, Pike_interpreter_reg, -  OFFSETOF(Pike_interpreter_struct, stack_pointer)); -  dirty_regs &= ~(1 << PIKE_SP_REG); +  mov_mem_reg(reg, OFFSETOF(svalue, type), REG_RAX); +  mov_mem_reg(reg, OFFSETOF(svalue, u.refs), REG_RCX); +  mov_reg_mem(REG_RAX, sp_reg, OFFSETOF(svalue, type)); +  and_reg_imm(REG_RAX, 0x1f); +  mov_reg_mem(REG_RCX, sp_reg, OFFSETOF(svalue, u.refs)); +  cmp_reg_imm(REG_RAX, MAX_REF_TYPE); +  jg(&label_A); +  add_imm_mem( 1, REG_RCX,OFFSETOF(pike_string, refs)); +  LABEL_A; +  amd64_add_sp( 1 );   } - } +       static void amd64_push_int(INT64 value, int subtype)   {    amd64_load_sp_reg(); -  AMD64_LOAD_IMM32(REG_RAX, (subtype<<16) + PIKE_T_INT); -  AMD64_MOVE_REG_TO_RELADDR(REG_RAX, sp_reg, OFFSETOF(svalue, type)); -  AMD64_LOAD_IMM(REG_RAX, value); -  AMD64_MOVE_REG_TO_RELADDR(REG_RAX, sp_reg, OFFSETOF(svalue, u.integer)); -  AMD64_ADD_IMM32(sp_reg, sizeof(struct svalue)); -  dirty_regs |= 1 << sp_reg; -  /* FIXME: Deferred writing of Pike_sp doen't seem to work reliably yet. */ -  if (dirty_regs & (1 << PIKE_SP_REG)) { -  AMD64_MOVE_REG_TO_RELADDR(PIKE_SP_REG, Pike_interpreter_reg, -  OFFSETOF(Pike_interpreter_struct, stack_pointer)); -  dirty_regs &= ~(1 << PIKE_SP_REG); +  mov_imm_mem((subtype<<16) + PIKE_T_INT, sp_reg, OFFSETOF(svalue, type)); +  mov_imm_mem(value, sp_reg, OFFSETOF(svalue, u.integer)); +  amd64_add_sp( 1 );   } -  +  + static void amd64_push_int_reg(enum amd64_reg reg ) + { +  if( reg == REG_RCX ) Pike_fatal( "Source clobbered in push_int_reg\n"); +  amd64_load_sp_reg(); +  mov_imm_mem( PIKE_T_INT, sp_reg, OFFSETOF(svalue, type)); +  mov_reg_mem( reg, sp_reg, OFFSETOF(svalue, u.integer)); +  amd64_add_sp( 1 );   }      static void amd64_mark(int offset)
751:    amd64_load_sp_reg();    amd64_load_mark_sp_reg();    if (offset) { -  AMD64_ADD_REG_IMM32(sp_reg, -offset * sizeof(struct svalue), REG_RAX); -  AMD64_MOVE_REG_TO_RELADDR(REG_RAX, mark_sp_reg, 0x00); +  add_reg_imm_reg(sp_reg, -offset * sizeof(struct svalue), REG_RAX); +  mov_reg_mem(REG_RAX, mark_sp_reg, 0);    } else { -  AMD64_MOVE_REG_TO_RELADDR(sp_reg, mark_sp_reg, 0x00); +  mov_reg_mem(sp_reg, mark_sp_reg, 0);    } -  AMD64_ADD_IMM32(mark_sp_reg, sizeof(struct svalue *)); -  dirty_regs |= 1 << mark_sp_reg; -  /* FIXME: Deferred writing of Pike_mark_sp doen't seem to work reliably yet. */ -  if (dirty_regs & (1 << PIKE_MARK_SP_REG)) { -  AMD64_MOVE_REG_TO_RELADDR(PIKE_MARK_SP_REG, Pike_interpreter_reg, -  OFFSETOF(Pike_interpreter_struct, mark_stack_pointer)); -  dirty_regs &= ~(1 << PIKE_MARK_SP_REG); +  amd64_add_mark_sp( 1 );   } -  +  + static void mov_sval_type(enum amd64_reg src, enum amd64_reg dst ) + { +  mov_mem32_reg( src, OFFSETOF(svalue,type), dst); +  and_reg_imm( dst, 0x1f );   }    - static void amd64_pop_mark(void) +  + static void amd64_call_c_function(void *addr)   { -  amd64_load_mark_sp_reg(); -  AMD64_ADD_IMM32(mark_sp_reg, -(int)sizeof(struct svalue *)); -  dirty_regs |= 1 << mark_sp_reg; -  /* FIXME: Deferred writing of Pike_mark_sp doen't seem to work reliably yet. */ -  if (dirty_regs & (1 << PIKE_MARK_SP_REG)) { -  AMD64_MOVE_REG_TO_RELADDR(PIKE_MARK_SP_REG, Pike_interpreter_reg, -  OFFSETOF(Pike_interpreter_struct, mark_stack_pointer)); -  dirty_regs &= ~(1 << PIKE_MARK_SP_REG); +  flush_dirty_regs(); +  call_imm(addr); +  next_reg = REG_RAX;   } -  +  + static void amd64_free_svalue(enum amd64_reg src, int guaranteed_ref ) + { +  LABELS(); +  if( src == REG_RAX ) +  Pike_fatal("Clobbering RAX for free-svalue\n"); +  /* load type -> RAX */ +  mov_sval_type( src, REG_RAX ); +  +  /* if RAX > MAX_REF_TYPE+1 */ +  cmp_reg_imm( REG_RAX,MAX_REF_TYPE); +  jg( &label_A ); +  +  /* Load pointer to refs -> RAX */ +  mov_mem_reg( src, OFFSETOF(svalue, u.refs), REG_RAX); +  /* if( !--*RAX ) */ +  add_mem32_imm( REG_RAX, OFFSETOF(pike_string,refs), -1); +  if( !guaranteed_ref ) +  { +  /* We need to see if refs got to 0. */ +  jnz( &label_A ); +  /* else, call really_free_svalue */ +  if( src != ARG1_REG ) +  mov_reg_reg( src, ARG1_REG ); +  amd64_call_c_function(really_free_svalue);    } -  +  LABEL_A; + }    - static void amd64_push_string(int strno, int subtype) + void amd64_ref_svalue( enum amd64_reg src )   { -  +  LABELS(); +  if( src == REG_RAX ) Pike_fatal("Clobbering src in ref_svalue\n"); +  +  mov_sval_type( src, REG_RAX ); +  +  /* if RAX > MAX_REF_TYPE+1 */ +  cmp_reg_imm(REG_RAX, MAX_REF_TYPE ); +  jg( &label_A ); +  /* Load pointer to refs -> RAX */ +  mov_mem_reg( src, OFFSETOF(svalue, u.refs), REG_RAX); +  /* *RAX++ */ +  add_mem32_imm( REG_RAX, OFFSETOF(pike_string,refs), 1); +  LABEL_A; + } +  + void amd64_assign_local( int b ) + {    amd64_load_fp_reg();    amd64_load_sp_reg(); -  AMD64_MOVE_RELADDR_TO_REG(fp_reg, OFFSETOF(pike_frame, context), REG_RAX); -  AMD64_LOAD_IMM32(REG_RCX, (subtype<<16) | PIKE_T_STRING); -  AMD64_MOVE_RELADDR_TO_REG(REG_RAX, OFFSETOF(inherit, prog), REG_RAX); -  AMD64_MOVE_REG_TO_RELADDR(REG_RCX, sp_reg, OFFSETOF(svalue, type)); -  AMD64_MOVE_RELADDR_TO_REG(REG_RAX, OFFSETOF(program, strings), REG_RAX); -  AMD64_ADD_IMM32(sp_reg, sizeof(struct svalue)); -  AMD64_MOVE_RELADDR_TO_REG(REG_RAX, strno * sizeof(struct pike_string *), -  REG_RAX); -  AMD64_MOVE_REG_TO_RELADDR(REG_RAX, sp_reg, -  (INT32)OFFSETOF(svalue, u.string) - -  (INT32)sizeof(struct svalue)); -  AMD64_ADD_VAL_TO_RELADDR(1, OFFSETOF(pike_string, refs), REG_RAX); -  dirty_regs |= 1 << sp_reg; -  /* FIXME: Deferred writing of Pike_sp doen't seem to work reliably yet. */ -  if (dirty_regs & (1 << PIKE_SP_REG)) { -  AMD64_MOVE_REG_TO_RELADDR(PIKE_SP_REG, Pike_interpreter_reg, -  OFFSETOF(Pike_interpreter_struct, stack_pointer)); -  dirty_regs &= ~(1 << PIKE_SP_REG); +  +  mov_mem_reg( fp_reg, OFFSETOF(pike_frame, locals), ARG1_REG); +  add_reg_imm( ARG1_REG,b*sizeof(struct svalue) ); +  mov_reg_reg( ARG1_REG, REG_RBX ); +  +  // Free old svalue +  amd64_free_svalue(ARG1_REG, 0); +  +  // Copy sp[-1] -> local +  mov_mem_reg(sp_reg, -1*sizeof(struct svalue), REG_RAX); +  mov_mem_reg(sp_reg, -1*sizeof(struct svalue)+sizeof(long), REG_RCX); +  +  mov_reg_mem( REG_RAX, REG_RBX, 0 ); +  mov_reg_mem( REG_RCX, REG_RBX, sizeof(long) );   } -  +  + static void amd64_pop_mark(void) + { +  amd64_add_mark_sp( -1 );   }    -  + static void amd64_push_string(int strno, int subtype) + { +  amd64_load_fp_reg(); +  amd64_load_sp_reg(); +  mov_mem_reg(fp_reg, OFFSETOF(pike_frame, context), REG_RAX); +  mov_mem_reg(REG_RAX, OFFSETOF(inherit, prog), REG_RAX); +  mov_mem_reg(REG_RAX, OFFSETOF(program, strings), REG_RAX); +  mov_mem_reg(REG_RAX, strno * sizeof(struct pike_string *), REG_RAX); +  mov_imm_mem((subtype<<16) | PIKE_T_STRING, sp_reg, OFFSETOF(svalue, type)); +  mov_reg_mem(REG_RAX, sp_reg,(INT32)OFFSETOF(svalue, u.string)); +  add_imm_mem( 1, REG_RAX, OFFSETOF(pike_string, refs)); +  +  amd64_add_sp(1); + } +    static void amd64_push_local_function(int fun)   {    amd64_load_fp_reg();    amd64_load_sp_reg(); -  AMD64_MOVE_RELADDR_TO_REG(fp_reg, OFFSETOF(pike_frame, context), REG_RAX); -  AMD64_MOVE_RELADDR_TO_REG(fp_reg, OFFSETOF(pike_frame, current_object), +  mov_mem_reg(fp_reg, OFFSETOF(pike_frame, context), REG_RAX); +  mov_mem_reg(fp_reg, OFFSETOF(pike_frame, current_object),    REG_RCX); -  AMD64_MOVE32_RELADDR_TO_REG(REG_RAX, OFFSETOF(inherit, identifier_level), +  mov_mem32_reg(REG_RAX, OFFSETOF(inherit, identifier_level),    REG_RAX); -  AMD64_MOVE_REG_TO_RELADDR(REG_RCX, sp_reg, OFFSETOF(svalue, u.object)); -  AMD64_ADD_IMM32(REG_RAX, fun); -  AMD64_ADD_VAL_TO_RELADDR(1, (INT32)OFFSETOF(object, refs), REG_RCX); -  AMD64_SHL_IMM8(REG_RAX, 16); -  AMD64_ADD_IMM32(REG_RAX, PIKE_T_FUNCTION); -  AMD64_MOVE_REG_TO_RELADDR(REG_RAX, sp_reg, OFFSETOF(svalue, type)); -  AMD64_ADD_IMM32(sp_reg, sizeof(struct svalue)); -  dirty_regs |= 1 << sp_reg; -  /* FIXME: Deferred writing of Pike_sp doen't seem to work reliably yet. */ -  if (dirty_regs & (1 << PIKE_SP_REG)) { -  AMD64_MOVE_REG_TO_RELADDR(PIKE_SP_REG, Pike_interpreter_reg, -  OFFSETOF(Pike_interpreter_struct, stack_pointer)); -  dirty_regs &= ~(1 << PIKE_SP_REG); +  mov_reg_mem(REG_RCX, sp_reg, OFFSETOF(svalue, u.object)); +  add_reg_imm(REG_RAX, fun); +  add_imm_mem( 1, REG_RCX,(INT32)OFFSETOF(object, refs)); +  shl_reg_imm(REG_RAX, 16); +  add_reg_imm(REG_RAX, PIKE_T_FUNCTION); +  mov_reg_mem(REG_RAX, sp_reg, OFFSETOF(svalue, type)); +  amd64_add_sp(1);   } - } +     - static void amd64_call_c_function(void *addr) - { -  CALL_ABSOLUTE(addr); -  next_reg = REG_RAX; -  CLEAR_REGS(); - } -  +    static void amd64_stack_error(void)   {    Pike_fatal("Stack error\n");
845:   {    INT32 tmp = PIKE_PC, disp;    -  if (amd64_prev_stored_pc == -1) { -  enum amd64_reg tmp_reg = alloc_reg(0); +  if(amd64_prev_stored_pc == - 1) +  { +  enum amd64_reg tmp_reg = REG_RAX;    amd64_load_fp_reg(); -  AMD64_LOAD_RIP32(tmp - (PIKE_PC + 7), tmp_reg); -  AMD64_MOVE_REG_TO_RELADDR(tmp_reg, fp_reg, OFFSETOF(pike_frame, pc)); +  mov_rip_imm_reg(tmp - PIKE_PC, tmp_reg); +  mov_reg_mem(tmp_reg, fp_reg, OFFSETOF(pike_frame, pc));   #ifdef PIKE_DEBUG    if (a_flag >= 60) -  fprintf (stderr, "pc %d update pc via call\n", tmp); +  fprintf (stderr, "pc %d update pc via lea\n", tmp);   #endif -  DEALLOC_REG (tmp_reg); +  amd64_prev_stored_pc = PIKE_PC;    } -  else if ((disp = tmp - amd64_prev_stored_pc)) { +  else if ((disp = tmp - amd64_prev_stored_pc)) +  {   #ifdef PIKE_DEBUG    if (a_flag >= 60)    fprintf (stderr, "pc %d update pc relative: %d\n", tmp, disp);   #endif    amd64_load_fp_reg(); -  AMD64_ADD_VAL_TO_RELADDR (disp, OFFSETOF (pike_frame, pc), fp_reg); +  add_imm_mem(disp, fp_reg, OFFSETOF (pike_frame, pc));    }    else {   #ifdef PIKE_DEBUG
870:    fprintf (stderr, "pc %d update pc - already up-to-date\n", tmp);   #endif    } -  amd64_prev_stored_pc = tmp; + #if 0   #ifdef PIKE_DEBUG    if (d_flag) {    /* Check that the stack keeps being 16 byte aligned. */ -  AMD64_MOV_REG(REG_RSP, REG_RAX); -  AMD64_AND_IMM32(REG_RAX, 0x08); +  mov_reg_reg(REG_RSP, REG_RAX); +  and_reg_imm(REG_RAX, 0x08);    AMD64_JE(0x09); -  CALL_ABSOLUTE(amd64_stack_error); +  call_imm(amd64_stack_error);    }   #endif -  + #endif   }      
903:    }   }    + static void sync_registers(int flags) + { +  maybe_update_pc(); +  flush_dirty_regs(); +  +  if (flags & I_UPDATE_SP) sp_reg = 0; +  if (flags & I_UPDATE_M_SP) mark_sp_reg = 0; +  if (flags & I_UPDATE_FP) fp_reg = 0; + } +  + static void amd64_call_c_opcode(void *addr, int flags) + { +  sync_registers(flags); +  call_imm( addr ); + } +  +    #ifdef PIKE_DEBUG   static void ins_debug_instr_prologue (PIKE_INSTR_T instr, INT32 arg1, INT32 arg2)   {
911: Inside #if defined(PIKE_DEBUG)
   maybe_update_pc();       if (flags & I_HASARG2) -  AMD64_LOAD_IMM32(ARG3_REG, arg2); +  mov_imm_reg(arg2, ARG3_REG);    if (flags & I_HASARG) -  AMD64_LOAD_IMM32(ARG2_REG, arg1); -  AMD64_LOAD_IMM32(ARG1_REG, instr); +  mov_imm_reg(arg1, ARG2_REG); +  mov_imm_reg(instr, ARG1_REG);       if (flags & I_HASARG2)    amd64_call_c_function (simple_debug_instr_prologue_2);
927:   #define ins_debug_instr_prologue(instr, arg1, arg2)   #endif    + static void amd64_push_this_object( ) + { +  amd64_load_fp_reg(); +  amd64_load_sp_reg(); +  +  mov_imm_mem( PIKE_T_OBJECT, sp_reg, OFFSETOF(svalue,type)); +  mov_mem_reg( fp_reg, OFFSETOF(pike_frame, current_object), REG_RAX ); +  mov_reg_mem( REG_RAX, sp_reg, OFFSETOF(svalue,u.object) ); +  add_mem32_imm( REG_RAX, (INT32)OFFSETOF(object, refs), 1); +  amd64_add_sp( 1 ); + } +  + void amd64_ins_branch_check_threads_etc() + { +  LABELS(); +  mov_imm_reg( (long)&fast_check_threads_counter, REG_RAX); +  add_mem32_imm( REG_RAX, 0, 1); +  mov_mem_reg( REG_RAX, 0, REG_RAX ); +  +  cmp_reg_imm( REG_RAX, 1024 ); +  jg( &label_A ); +  amd64_call_c_function(branch_check_threads_etc); + LABEL_A; + } +  +    void amd64_init_interpreter_state(void)   {    instrs[F_CATCH - F_OFFSET].address = inter_return_opcode_F_CATCH;
937:    int flags;    void *addr;    INT32 rel_addr = 0; +  LABELS(); +     b-=F_OFFSET;   #ifdef PIKE_DEBUG    if(b>255)
952:    {    /* Special argument for the F_CATCH instruction. */    addr = inter_return_opcode_F_CATCH; -  AMD64_LOAD_RIP32(0, ARG1_REG); /* Address for the POINTER. */ +  mov_rip_imm_reg(0, ARG1_REG); /* Address for the POINTER. */    rel_addr = PIKE_PC;    }    break;
1004:    return;    }    -  flush_dirty_regs(); -  if (flags & I_UPDATE_SP) sp_reg = 0; -  if (flags & I_UPDATE_M_SP) mark_sp_reg = 0; -  if (flags & I_UPDATE_FP) fp_reg = 0; +  amd64_call_c_opcode(addr,flags);    -  amd64_call_c_function(addr); +     if (instrs[b].flags & I_RETURN) { -  INT32 skip; +  LABELS(); +     if ((b + F_OFFSET) == F_RETURN_IF_TRUE) {    /* Kludge. We must check if the ret addr is -  * orig_addr + JUMP_EPILOGUE_SIZE. */ -  AMD64_LOAD_RIP32(JUMP_EPILOGUE_SIZE - 7, REG_RCX); +  * PC + JUMP_EPILOGUE_SIZE. */ +  mov_rip_imm_reg(JUMP_EPILOGUE_SIZE, REG_RCX);    } -  AMD64_CMP_REG_IMM32(REG_RAX, -1); -  AMD64_JNE(0); -  skip = (INT32)PIKE_PC; -  AMD64_POP(REG_RBX); // Stack padding. -  AMD64_POP(REG_RBX); -  AMD64_POP(REG_R12); -  AMD64_POP(REG_R13); -  AMD64_POP(REG_R14); -  AMD64_POP(REG_R15); -  AMD64_POP(REG_RBP); -  AMD64_RET(); -  Pike_compiler->new_program->program[skip-1] = ((INT32)PIKE_PC) - skip; +  cmp_reg_imm(REG_RAX, -1); +  jne(&label_A); +  if( ret_for_func ) +  { +  jmp_rel_imm( ret_for_func - PIKE_PC ); +  } +  else +  { +  ret_for_func = PIKE_PC; +  pop(REG_RBX); // Stack padding. +  pop(REG_RBX); +  pop(REG_R12); +  pop(REG_R13); +  pop(REG_R14); +  pop(REG_R15); +  pop(REG_RBP); +  ret(); +  } +  LABEL_A; +     if ((b + F_OFFSET) == F_RETURN_IF_TRUE) {    /* Kludge. We must check if the ret addr is    * orig_addr + JUMP_EPILOGUE_SIZE. */ -  AMD64_CMP_REG(REG_RAX, REG_RCX); -  AMD64_JE(0x02); -  AMD64_JUMP_REG(REG_RAX); +  cmp_reg_reg( REG_RAX, REG_RCX ); +  je( &label_A ); +  jmp_reg(REG_RAX); +  LABEL_A;    return;    }    }    if (flags & I_JUMP) { -  AMD64_JUMP_REG(REG_RAX); +  jmp_reg(REG_RAX);       if (b + F_OFFSET == F_CATCH) {    upd_pointer(rel_addr - 4, PIKE_PC - rel_addr);
1060:    flags = instrs[off].flags;    if (!(flags & I_BRANCH)) return -1;    -  maybe_update_pc(); -  -  flush_dirty_regs(); -  -  if (flags & I_UPDATE_SP) sp_reg = 0; -  if (flags & I_UPDATE_M_SP) mark_sp_reg = 0; -  if (flags & I_UPDATE_FP) fp_reg = 0; -  +     if (op == F_BRANCH) {    ins_debug_instr_prologue(off, 0, 0);    if (backward_jump) { -  amd64_call_c_function(branch_check_threads_etc); +  //md64_call_c_function(branch_check_threads_etc); +  maybe_update_pc(); +  amd64_ins_branch_check_threads_etc();    }    add_to_program(0xe9);    ret=DO_NOT_WARN( (INT32) PIKE_PC );
1079:    return ret;    }    +  maybe_update_pc();    addr=instrs[off].address; -  amd64_call_c_function(addr); -  AMD64_TEST_REG(REG_RAX); +  amd64_call_c_opcode(addr, flags); +  test_reg(REG_RAX);       if (backward_jump) {    INT32 skip;    add_to_program (0x74); /* jz rel8 */    add_to_program (0); /* Bytes to skip. */    skip = (INT32)PIKE_PC; -  amd64_call_c_function (branch_check_threads_etc); +  amd64_ins_branch_check_threads_etc(); +  /* amd64_call_c_function (branch_check_threads_etc); */    add_to_program (0xe9); /* jmp rel32 */    ret = DO_NOT_WARN ((INT32) PIKE_PC);    PUSH_INT (0);
1096:    Pike_compiler->new_program->program[skip-1] = ((INT32)PIKE_PC - skip);    }    else { - #if 0 -  if ((cpu_vendor == PIKE_CPU_VENDOR_AMD) && -  (op == F_LOOP || op == F_FOREACH)) { -  /* FIXME: Slows down Intel PIII/x86 by 7%, speeds up Athlon XP by 22%. :P */ -  add_to_program (0x3e); /* Branch taken hint. */ -  } - #endif +     add_to_program (0x0f); /* jnz rel32 */    add_to_program (0x85);    ret = DO_NOT_WARN ((INT32) PIKE_PC);
1116:   {    maybe_update_pc();    switch(a) { +  case F_THIS_OBJECT: +  if( b == 0 ) +  { +  amd64_push_this_object(); +  return; +  } +  break; // Fallback to C-version    case F_NUMBER:    ins_debug_instr_prologue(a-F_OFFSET, b, 0);    amd64_push_int(b, 0);
1168:    ins_debug_instr_prologue(a-F_OFFSET, b, 0);    amd64_push_local_function(b);    return; +  +  case F_ASSIGN_LOCAL: +  ins_debug_instr_prologue(a-F_OFFSET, b, 0); +  amd64_assign_local(b); +  add_reg_imm_reg(sp_reg, -sizeof(struct svalue), ARG1_REG); +  amd64_ref_svalue(ARG1_REG); +  return; +  +  case F_ASSIGN_LOCAL_AND_POP: +  ins_debug_instr_prologue(a-F_OFFSET, b, 0); +  amd64_assign_local(b); +  amd64_add_sp(-1); +  return; +  +  case F_ASSIGN_GLOBAL: +  case F_ASSIGN_GLOBAL_AND_POP: +  /* arg1: pike_fp->current obj +  arg2: arg1+idenfier level +  arg3: Pike_sp-1 +  */ +  /* NOTE: We cannot simply do the same optimization as for +  ASSIGN_LOCAL_AND_POP with assign global, since assigning +  at times does not add references. +  +  We do know, however, that refs (should) never reach 0 when +  poping the stack. We can thus skip that part of pop_value +  */ +  ins_debug_instr_prologue(a-F_OFFSET, b, 0); +  amd64_load_fp_reg(); +  amd64_load_sp_reg(); +  +  mov_mem_reg(fp_reg, OFFSETOF(pike_frame, current_object), ARG1_REG); +  mov_mem_reg(fp_reg, OFFSETOF(pike_frame,context), ARG2_REG); +  mov_mem16_reg(ARG2_REG, OFFSETOF(inherit, identifier_level), ARG2_REG); +  +  add_reg_imm( ARG2_REG, b ); +  add_reg_imm_reg( sp_reg, -sizeof(struct svalue), ARG3_REG ); +  amd64_call_c_function( object_low_set_index ); +  +  if( a == F_ASSIGN_GLOBAL_AND_POP ) +  { +  /* assign done, pop. */ +  amd64_add_sp( -1 ); +  amd64_free_svalue( sp_reg, 1 ); +  } +  return; +  +  case F_SIZEOF_LOCAL: +  { +  LABELS(); +  ins_debug_instr_prologue(b,0,0); +  amd64_load_fp_reg(); +  amd64_load_sp_reg(); +  +  mov_mem_reg( fp_reg, OFFSETOF(pike_frame,locals), ARG1_REG); +  add_reg_imm( ARG1_REG, b*sizeof(struct svalue)); + #if 0 +  mov_sval_type( ARG1_REG, REG_RAX ); +  /* type in RAX, svalue in ARG1 */ +  cmp_reg_imm( REG_RAX, PIKE_T_ARRAY ); +  jne( &label_A ); +  /* It's an array */ +  /* move arg to point to the array */ +  mov_mem_reg( ARG1_REG, OFFSETOF(svalue, u.array ), ARG1_REG); +  /* load size -> RAX*/ +  mov_mem32_reg( ARG1_REG,OFFSETOF(array, size), REG_RAX ); +  jmp( &label_C ); +  LABEL_A; +  cmp_reg_imm( REG_RAX, PIKE_T_STRING ); +  jne( &label_B ); +  /* It's a string */ +  /* move arg to point to the string */ +  mov_mem_reg( ARG1_REG, OFFSETOF(svalue, u.string ), ARG1_REG); +  /* load size ->RAX*/ +  mov_mem32_reg( ARG1_REG,OFFSETOF(pike_string, len ), REG_RAX ); +  jmp( &label_C ); +  LABEL_B; + #endif +  /* It's something else, svalue already in ARG1. */ +  amd64_call_c_function( pike_sizeof ); +  amd64_load_sp_reg(); +  LABEL_C;/* all done, res in RAX */ +  /* Store result on stack */ +  amd64_push_int_reg( REG_RAX ); +  } +  return; +     case F_GLOBAL:    ins_debug_instr_prologue(a-F_OFFSET, b, 0);    amd64_load_fp_reg();    amd64_load_sp_reg(); -  AMD64_MOVE_RELADDR_TO_REG(fp_reg, OFFSETOF(pike_frame, context), ARG3_REG); -  AMD64_MOVE_RELADDR_TO_REG(fp_reg, OFFSETOF(pike_frame, current_object), +  mov_mem_reg(fp_reg, OFFSETOF(pike_frame, context), ARG3_REG); +  mov_mem_reg(fp_reg, OFFSETOF(pike_frame, current_object),    ARG2_REG); -  AMD64_MOV_REG(sp_reg, ARG1_REG); -  AMD64_MOVE32_RELADDR_TO_REG(ARG3_REG, OFFSETOF(inherit, identifier_level), +  mov_reg_reg(sp_reg, ARG1_REG); +  mov_mem32_reg(ARG3_REG, OFFSETOF(inherit, identifier_level),    ARG3_REG); -  AMD64_AND_IMM32(ARG3_REG, 0xffff); -  AMD64_ADD_IMM32(ARG3_REG, b); +  and_reg_imm(ARG3_REG, 0xffff); +  add_reg_imm(ARG3_REG, b);    flush_dirty_regs(); /* In case an error is thrown. */ -  CALL_ABSOLUTE(low_object_index_no_free); +  call_imm(low_object_index_no_free);    /* NB: We know that low_object_index_no_free() doesn't    * mess with the stack pointer. */ -  AMD64_ADD_IMM32(sp_reg, sizeof(struct svalue)); -  dirty_regs |= 1 << sp_reg; -  flush_dirty_regs(); +  amd64_add_sp(1);    return; -  +     case F_LOCAL:    ins_debug_instr_prologue(a-F_OFFSET, b, 0);    amd64_load_fp_reg();    amd64_load_sp_reg(); -  AMD64_MOVE_RELADDR_TO_REG(fp_reg, OFFSETOF(pike_frame, locals), REG_RCX); -  AMD64_ADD_IMM32(REG_RCX, b*sizeof(struct svalue)); +  mov_mem_reg(fp_reg, OFFSETOF(pike_frame, locals), REG_RCX); +  add_reg_imm(REG_RCX, b*sizeof(struct svalue));    amd64_push_svaluep(REG_RCX);    return; -  +  +  case F_CONSTANT: +  ins_debug_instr_prologue(a-F_OFFSET, b, 0); +  amd64_load_fp_reg(); +  amd64_load_sp_reg(); +  mov_mem_reg( fp_reg, OFFSETOF(pike_frame,context), REG_RCX ); +  mov_mem_reg( REG_RCX, OFFSETOF(inherit,prog), REG_RCX ); +  mov_mem_reg( REG_RCX, OFFSETOF(program,constants), REG_RCX ); +  add_reg_imm( REG_RCX, b*sizeof(struct program_constant) + +  OFFSETOF(program_constant,sval) ); +  amd64_push_svaluep( REG_RCX ); +  return; +  +  case F_GLOBAL_LVALUE: +  ins_debug_instr_prologue(a-F_OFFSET, b, 0); +  amd64_load_fp_reg(); +  amd64_load_sp_reg(); +  +  amd64_push_this_object( ); +  +  mov_imm_mem( T_OBJ_INDEX, sp_reg, OFFSETOF(svalue,type)); +  mov_mem_reg(fp_reg, OFFSETOF(pike_frame, context), REG_RAX); +  mov_mem16_reg( REG_RAX,OFFSETOF(inherit, identifier_level), REG_RAX); +  add_reg_imm( REG_RAX, b ); +  mov_reg_mem( REG_RAX, sp_reg, OFFSETOF(svalue,u.identifier) ); +  amd64_add_sp( 1 ); +  return; +  +  case F_LOCAL_LVALUE: +  ins_debug_instr_prologue(a-F_OFFSET, b, 0); +  amd64_load_fp_reg(); +  amd64_load_sp_reg(); +  +  /* &frame->locals[b] */ +  mov_mem_reg( fp_reg, OFFSETOF(pike_frame, locals), REG_RAX); +  add_reg_imm( REG_RAX, b*sizeof(struct svalue)); +  +  mov_imm_mem( T_SVALUE_PTR, sp_reg, OFFSETOF(svalue,type)); +  mov_reg_mem( REG_RAX, sp_reg, OFFSETOF(svalue,u.lval) ); +  mov_imm_mem( T_VOID, sp_reg, OFFSETOF(svalue,type)+sizeof(struct svalue)); +  amd64_add_sp( 2 ); +  return; +     case F_PROTECT_STACK:    ins_debug_instr_prologue(a-F_OFFSET, b, 0);    amd64_load_fp_reg(); -  AMD64_MOVE_RELADDR_TO_REG(fp_reg, OFFSETOF(pike_frame, locals), ARG1_REG); +  mov_mem_reg(fp_reg, OFFSETOF(pike_frame, locals), ARG1_REG);    if (b) { -  AMD64_ADD_REG_IMM32(ARG1_REG, sizeof(struct svalue) * b, ARG1_REG); +  add_reg_imm_reg(ARG1_REG, sizeof(struct svalue) * b, ARG1_REG);    } -  AMD64_MOVE_REG_TO_RELADDR(ARG1_REG, fp_reg, +  mov_reg_mem(ARG1_REG, fp_reg,    OFFSETOF(pike_frame, expendible));    return;    case F_MARK_AT:    ins_debug_instr_prologue(a-F_OFFSET, b, 0);    amd64_load_fp_reg();    amd64_load_mark_sp_reg(); -  AMD64_MOVE_RELADDR_TO_REG(fp_reg, OFFSETOF(pike_frame, locals), ARG1_REG); +  mov_mem_reg(fp_reg, OFFSETOF(pike_frame, locals), ARG1_REG);    if (b) { -  AMD64_ADD_REG_IMM32(ARG1_REG, sizeof(struct svalue) * b, ARG1_REG); +  add_reg_imm_reg(ARG1_REG, sizeof(struct svalue) * b, ARG1_REG);    } -  AMD64_MOVE_REG_TO_RELADDR(ARG1_REG, mark_sp_reg, 0x00); -  AMD64_ADD_IMM32(mark_sp_reg, sizeof(struct svalue *)); +  mov_reg_mem(ARG1_REG, mark_sp_reg, 0x00); +  add_reg_imm(mark_sp_reg, sizeof(struct svalue *));    dirty_regs |= 1 << mark_sp_reg;    /* FIXME: Deferred writing of Pike_mark_sp doen't seem to work reliably yet. */    if (dirty_regs & (1 << PIKE_MARK_SP_REG)) { -  AMD64_MOVE_REG_TO_RELADDR(PIKE_MARK_SP_REG, Pike_interpreter_reg, +  mov_reg_mem(PIKE_MARK_SP_REG, Pike_interpreter_reg,    OFFSETOF(Pike_interpreter_struct, mark_stack_pointer));    dirty_regs &= ~(1 << PIKE_MARK_SP_REG);    }
1231:      int amd64_ins_f_jump_with_arg(unsigned int op, INT32 a, int backward_jump)   { +  LABELS();    if (!(instrs[op - F_OFFSET].flags & I_BRANCH)) return -1; -  +  +  switch( op ) +  { +  case F_BRANCH_IF_NOT_LOCAL: +  case F_BRANCH_IF_LOCAL: +  ins_debug_instr_prologue(op-F_OFFSET, a, 0); +  amd64_load_fp_reg(); +  mov_mem_reg( fp_reg, OFFSETOF(pike_frame, locals), REG_RAX); +  add_reg_imm( REG_RAX, a*sizeof(struct svalue)); +  /* if( type == PIKE_T_OBJECT ) +  call c version... +  else +  u.integer -> RAX +  */ +  mov_sval_type( REG_RAX, REG_RCX ); +  cmp_reg_imm( REG_RCX, PIKE_T_OBJECT ); +  jne( &label_A ); +  +  update_arg1(a); +  /* Note: Always call IF_LOCAL, the negation is done below. */ +  amd64_call_c_opcode( instrs[F_BRANCH_IF_LOCAL-F_OFFSET].address, +  instrs[F_BRANCH_IF_LOCAL-F_OFFSET].flags ); +  jmp( &label_B ); +  LABEL_A; +  mov_mem_reg( REG_RAX, OFFSETOF(svalue, u.integer ), REG_RAX ); +  LABEL_B; +  test_reg( REG_RAX ); +  if( op == F_BRANCH_IF_LOCAL ) +  return jnz_imm_rel32(0); +  return jz_imm_rel32(0); +  } +     maybe_update_pc();    update_arg1(a);    return amd64_ins_f_jump(op, backward_jump);
1250:    ins_f_byte_with_2_args(F_EXTERNAL, b, c);    return;    case F_2_LOCALS: -  ins_f_byte_with_arg(F_LOCAL, b); -  ins_f_byte_with_arg(F_LOCAL, c); + #if 1 +  ins_debug_instr_prologue(a-F_OFFSET, b, 0); +  amd64_load_fp_reg(); +  amd64_load_sp_reg(); +  mov_mem_reg(fp_reg, OFFSETOF(pike_frame, locals), REG_R8); +  add_reg_imm( REG_R8, b*sizeof(struct svalue) ); +  amd64_push_svaluep(REG_R8); +  add_reg_imm( REG_R8, (c-b)*sizeof(struct svalue) ); +  amd64_push_svaluep(REG_R8); + #else +  ins_f_byte_with_arg( F_LOCAL, b ); +  ins_f_byte_with_arg( F_LOCAL, c ); + #endif    return; - #if 0 +     case F_INIT_FRAME:    ins_debug_instr_prologue(a-F_OFFSET, b, c);    amd64_load_fp_reg(); -  AMD64_LOAD_IMM32(ARG1_REG, b); -  // FIXME: 16-bit store, or join b & c into a single 32-bit store. -  AMD64_MOVE16_REG_TO_RELADDR(ARG1_REG, fp_reg, -  OFFSETOF(pike_frame, num_args)); -  if (b != c) { -  AMD64_LOAD_IMM32(ARG1_REG, c); -  } -  AMD64_MOVE16_REG_TO_RELADDR(ARG1_REG, fp_reg, -  OFFSETOF(pike_frame, num_locals)); +  +  if(OFFSETOF(pike_frame, num_locals) != OFFSETOF(pike_frame, num_args)-2 ) +  Pike_fatal("This code does not with unless num_args\n" +  "directly follows num_locals in struct pike_frame\n"); +  +  mov_imm_mem32( (b<<16)|c, fp_reg, OFFSETOF(pike_frame, num_locals));    return; - #endif +     }    update_arg2(c);    update_arg1(b);