pike.git / src / code / amd64.c

version» Context lines:

pike.git/src/code/amd64.c:71:    /* 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;    l->addr = PIKE_PC;   }    + 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 modrm( int mod, int r, int m )   { -  add_to_program( ((mod<<6) | ((r&0x7)<<3) | (m&0x7)) ); +  ib( ((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) ); +  ib( (scale<<6) | ((index&0x7)<<3) | (base&0x7) );   }    -  +  + static void modrm_sib( int mod, int r, int m ) + { +  modrm( mod, r, m ); +  if( (m&7) == REG_RSP) +  sib(0, REG_RSP, REG_RSP ); + } +    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 ) + static void offset_modrm_sib( int offset, int r, int m )   { -  add_to_program( x ); +  /* OFFSET */ +  if( offset < -128 || offset > 127 ) +  { +  modrm_sib( 2, r, m ); +  id( offset );    } -  - static void iw( short x ) +  else if( offset || (m&7) == REG_RSP || (m&7) == REG_RBP )    { -  add_to_program( x>>8 ); -  add_to_program( x ); +  modrm_sib( 1, r, m ); +  ib( offset );    } -  - static void id( int x ) +  else    { -  add_to_program( (x)&0xff ); -  add_to_program( (x>>8)&0xff ); -  add_to_program( (x>>16)&0xff ); -  add_to_program( (x>>24)&0xff ); +  modrm_sib( 0, r, m );    } -  + }    - /* 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));   }
pike.git/src/code/amd64.c:145:    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 ); -  -  /* 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 ); -  if ((from_reg & 0x7) == 0x4) { -  /* r12 and RSP trigger use of the SIB byte. */ -  sib(0, 4, from_reg); +  offset_modrm_sib(offset, to_reg, from_reg );   } -  } -  else -  { -  if( offset < 128 && offset >= -128 ) -  { -  modrm( 1, to_reg, from_reg ); -  if ((from_reg & 0x7) == 0x4) { -  /* r12 and RSP trigger use of the SIB byte. */ -  sib(0, 4, from_reg); -  } -  ib( offset ); -  } -  else -  { -  modrm( 2, to_reg, from_reg ); -  if ((from_reg & 0x7) == 0x4) { -  /* r12 and RSP trigger use of the SIB byte. */ -  sib(0, 4, from_reg); -  } -  id(offset); -  } -  } - } +       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 );   }    - static void mov_mem32_reg( enum amd64_reg from_reg, ptrdiff_t offset, enum amd64_reg to_reg ) + static void xor_reg_reg( enum amd64_reg reg1, enum amd64_reg reg2 )   { -  rex( 0, to_reg, 0, from_reg ); -  low_mov_mem_reg( from_reg, offset, to_reg ); +  rex(1,reg1,0,reg2); +  opcode( 0x31 ); +  modrm(3,reg1,reg2);   }      static void and_reg_imm( enum amd64_reg reg, int imm32 )   {    rex( 1, 0, 0, reg );       if( imm32 < -0x80 || imm32 > 0x7f )    {    if( reg == REG_RAX )    {
pike.git/src/code/amd64.c:218:    }    }    else    {    add_to_program(0x83); /* AND REG,imm8 */    modrm( 3, 4, reg );    ib( imm32 );    }   }    + 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 ); + } +    static void mov_mem16_reg( enum amd64_reg from_reg, ptrdiff_t offset, enum amd64_reg to_reg )   { -  /* FIXME: Really implement... */ +  /* +  Actually doing a 16-bit read seems slower.. +  */    mov_mem32_reg( from_reg, offset, to_reg ); -  and_reg_imm( to_reg, 0xffff ); +  and_reg_imm(to_reg, 0xffff);   }      static void add_reg_imm( enum amd64_reg src, int imm32);      static void shl_reg_imm( enum amd64_reg from_reg, int shift )   {    rex( 1, from_reg, 0, 0 );    if( shift == 1 )    {    opcode( 0xd1 ); /* SAL */    modrm( 3, 4, from_reg );    }    else    {    opcode( 0xc1 );    modrm( 3, 4, from_reg );    ib( shift );    }   }    - static void xor_reg_reg( enum amd64_reg reg1, enum amd64_reg reg2 ) - { -  rex(1,reg1,0,reg2); -  opcode( 0x31 ); -  modrm(3,reg1,reg2); - } -  +    static void clear_reg( enum amd64_reg reg )   {    xor_reg_reg( reg, reg );   }      static void neg_reg( enum amd64_reg reg )   {    rex(1,0,0,reg);    opcode(0xf7);    modrm(3,3,reg);
pike.git/src/code/amd64.c:280:    }    else    {    rex(1,0,0,reg);    opcode( 0xc7 ); /* mov imm32 -> reg/m 64, SE*/    modrm( 3,0,reg );    id( (int)imm );    }   }    - static void mov_reg_mem( enum amd64_reg from_reg, enum amd64_reg to_reg, ptrdiff_t offset ) + static void low_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 ); -  +  offset_modrm_sib( offset, from_reg, to_reg ); + }    -  if( !offset && ((to_reg&7) != REG_RBP) ) + static void mov_reg_mem( enum amd64_reg from_reg, enum amd64_reg to_reg, ptrdiff_t offset )   { -  modrm( 0, from_reg, to_reg ); -  if( (to_reg&7) == REG_RSP) -  sib(0, REG_RSP, REG_RSP ); +  rex(1, from_reg, 0, to_reg ); +  low_mov_reg_mem( from_reg, to_reg, offset );   } -  else +  + static void mov_reg_mem32( enum amd64_reg from_reg, enum amd64_reg to_reg, ptrdiff_t offset )   { -  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 ); +  rex(0, from_reg, 0, to_reg ); +  low_mov_reg_mem( from_reg, to_reg, offset );   } -  else +  + static void mov_reg_mem16( enum amd64_reg from_reg, enum amd64_reg to_reg, ptrdiff_t offset )   { -  modrm( 2, from_reg, to_reg ); -  if( (to_reg&7) == REG_RSP ) -  sib(0, REG_RSP, REG_RSP ); -  id( offset ); +  opcode( 0x66 ); +  rex(0, from_reg, 0, to_reg ); +  low_mov_reg_mem( from_reg, to_reg, offset );   } -  } - } +     -  +  +    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 ); -  } +  offset_modrm_sib( offset, 0, to_reg );    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 );    }   }          - 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 ); -  -  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 ); -  } -  } - } -  -  +    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 ); -  } +  offset_modrm_sib( offset, 0, to_reg );    id( imm );   }    -  + static void sub_reg_imm( enum amd64_reg reg, int imm32 ); +    static void add_reg_imm( enum amd64_reg reg, int imm32 )   {    if( !imm32 ) return; -  +  if( imm32 < 0 ) +  { +  /* This makes the disassembly easier to read. */ +  sub_reg_imm( reg, -imm32 ); +  return; +  }       rex( 1, 0, 0, reg );       if( imm32 < -0x80 || imm32 > 0x7f )    {    if( reg == REG_RAX )    {    opcode( 0x05 ); /* ADD rax,imm32 */    id( imm32 );    }
pike.git/src/code/amd64.c:425:    }    }    else    {    add_to_program(0x83); /* ADD REG,imm8 */    modrm( 3, 0, reg );    ib( imm32 );    }   }    - static void add_mem32_imm( enum amd64_reg reg, int offset, int imm32 ) +  + static void low_add_mem_imm(int w, 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 ); +  rex( w, 0, 0, reg );       if( r2 ) imm32 = -imm32;       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 ); -  } +  offset_modrm_sib( offset, r2, reg );    if( imm32 != 1 )    {    if( large )    id( imm32 );    else    ib( imm32 );    }   }    - static void add_mem_imm( enum amd64_reg reg, int offset, int imm32 ) + 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( 1, 0, 0, reg ); -  -  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; +  low_add_mem_imm( 0, reg, offset, imm32 );   }    -  if( !offset && (reg&7) != REG_RSP ) + static void add_mem_imm( enum amd64_reg reg, int offset, int imm32 )   { -  modrm( 0, r2, reg ); +  low_add_mem_imm( 1, reg, offset, imm32 );   } -  else if( offset < -128 || offset > 127 ) -  { -  modrm( 2, r2, reg ); -  if( (reg&7) == REG_RSP ) -  sib(0, REG_RSP, REG_RSP ); -  id( offset ); -  } -  else -  { -  modrm( 1, r2, reg ); -  if( (reg&7) == REG_RSP ) -  sib(0, REG_RSP, REG_RSP ); -  ib( offset ); -  } -  if( imm32 != 1 && !r2 ) -  { -  if( large ) -  id( imm32 ); -  else -  ib( imm32 ); -  } - } +     -  - static void sub_mem32_imm( enum amd64_reg reg, int offset, int imm32 ) - { -  add_mem32_imm( reg, offset, -imm32 ); - } -  +    static void add_mem8_imm( enum amd64_reg reg, int offset, int imm32 )   {    int r2 = imm32 == -1 ? 1 : 0;    if( !imm32 ) return;    rex( 0, 0, 0, reg );       if( imm32 == 1 || imm32 == -1 )    opcode( 0xfe ); /* INCL r/m8 */    else if( imm32 >= -128 && imm32 < 128 )    opcode( 0x80 ); /* ADD imm8,r/m32 */    else    Pike_fatal("Not sensible");    -  if( !offset && (reg&7) != REG_RSP ) -  { -  modrm( 0, r2, reg ); -  } -  else if( offset < -128 || offset > 127 ) -  { -  modrm( 2, r2, reg ); -  if( (reg&7) == REG_RSP ) -  sib(0, REG_RSP, REG_RSP ); -  id( offset ); -  } -  else -  { -  modrm( 1, r2, reg ); -  if( (reg&7) == REG_RSP ) -  sib(0, REG_RSP, REG_RSP ); -  ib( offset ); -  } +  offset_modrm_sib( offset, r2, reg );    if( imm32 != 1 && !r2 )    {    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;    -  +  if( imm32 < 0 ) +  /* This makes the disassembly easier to read. */ +  return add_reg_imm( reg, -imm32 ); +     rex( 1, 0, 0, reg );       if( imm32 < -0x80 || imm32 > 0x7f )    {    if( reg == REG_RAX )    {    opcode( 0x2d ); /* SUB rax,imm32 */    id( imm32 );    }    else
pike.git/src/code/amd64.c:583:    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 )
pike.git/src/code/amd64.c:709:    rex(1,reg2,0,reg);    opcode( 0x29 );    modrm( 3, reg2, reg );   }      /* dst += *(src+off) */   static void add_reg_mem( enum amd64_reg dst, enum amd64_reg src, long off )   {    rex(1,dst,0,src);    opcode( 0x3 ); -  if( off < 0x7f && off > -0x80 ) -  { -  modrm( 1, dst, src ); -  if ((src & 0x7) == 0x4) { -  sib(0, 4, src); +  offset_modrm_sib( off, dst, src );   } -  ib( off ); -  } -  else -  { -  modrm( 2, dst, src ); -  if ((src & 0x7) == 0x4) { -  sib(0, 4, src); -  } -  id( off ); -  } - } +          /* dst -= *(src+off) */   static void sub_reg_mem( enum amd64_reg dst, enum amd64_reg src, long off )   {    rex(1,dst,0,src);    opcode( 0x2b ); -  if( off < 0x7f && off > -0x80 ) -  { -  modrm( 1, dst, src ); -  if ((src & 0x7) == 0x4) { -  sib(0, 4, src); +  offset_modrm_sib( off, dst, src );   } -  ib( off ); -  } -  else -  { -  modrm( 2, dst, src ); -  if ((src & 0x7) == 0x4) { -  sib(0, 4, src); -  } -  id( off ); -  } - } +          /* 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 )
pike.git/src/code/amd64.c:773:    }    else    {    if( !imm32 )    {    mov_reg_reg( src, dst );    return;    }    rex(1,dst,0,src);    opcode( 0x8d ); /* LEA r64,m */ -  if( imm32 <= 0x7f && imm32 >= -0x80 ) -  { -  modrm(1,dst,src); -  ib( imm32 ); +  offset_modrm_sib( imm32, dst, src );    } -  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 );
pike.git/src/code/amd64.c:813:    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_modrm_sib( offset, r2, reg );    -  /* 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 );    }   }   
pike.git/src/code/amd64.c:1098:    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 so, call really_free_svalue */    if( src != ARG1_REG )    mov_reg_reg( src, ARG1_REG );    amd64_call_c_function(really_free_svalue);    }    LABEL_A;   }    -  + /* Type already in RAX */ + static void amd64_free_svalue_type(enum amd64_reg src, enum amd64_reg type, +  int guaranteed_ref ) + { +  LABELS(); +  /* if type > MAX_REF_TYPE+1 */ +  if( src == REG_RAX ) +  Pike_fatal("Clobbering RAX for free-svalue\n"); +  cmp_reg_imm(type,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 ); +  /* if so, call really_free_svalue */ +  if( src != ARG1_REG ) +  mov_reg_reg( src, ARG1_REG ); +  amd64_call_c_function(really_free_svalue); +  } +  LABEL_A; + } +    void amd64_ref_svalue( enum amd64_reg src, int already_have_type )   {    LABELS();    if( src == REG_RAX ) Pike_fatal("Clobbering src in ref_svalue\n");    if( !already_have_type )    mov_sval_type( src, REG_RAX );    else    and_reg_imm( REG_RAX, 0x1f );       /* if RAX > MAX_REF_TYPE+1 */
pike.git/src/code/amd64.c:1644:   #define START_JUMP() do{ \    ins_debug_instr_prologue(off, 0, 0); \    if (backward_jump) { \    maybe_update_pc(); \    amd64_ins_branch_check_threads_etc(); \    } \    } while(0)       switch( op )    { +  case F_QUICK_BRANCH_WHEN_ZERO: +  case F_QUICK_BRANCH_WHEN_NON_ZERO: +  START_JUMP(); +  amd64_load_sp_reg(); +  amd64_add_sp( -1 ); +  mov_mem_reg( sp_reg, 8, REG_RAX ); +  test_reg(REG_RAX); +  if( op == F_QUICK_BRANCH_WHEN_ZERO ) +  return jz_imm_rel32(0); +  return jnz_imm_rel32(0); +  +  case F_BRANCH_WHEN_ZERO: +  case F_BRANCH_WHEN_NON_ZERO: +  START_JUMP(); +  amd64_load_sp_reg(); +  mov_mem16_reg( sp_reg, -sizeof(struct svalue), REG_RAX ); +  cmp_reg_imm( REG_RAX, PIKE_T_OBJECT ); +  je( &label_A ); +  +  amd64_add_sp( -1 ); +  mov_mem_reg( sp_reg, 8, REG_RBX ); +  amd64_free_svalue_type( sp_reg, REG_RAX, 0 ); +  test_reg( REG_RBX ); +  jmp( &label_B ); +  +  LABEL_A; /* It is an object. Use the C version. */ +  amd64_call_c_opcode(instrs[F_BRANCH_WHEN_ZERO-F_OFFSET].address, +  instrs[F_BRANCH_WHEN_ZERO-F_OFFSET].flags ); +  cmp_reg_imm( REG_RAX, -1 ); +  +  LABEL_B; /* Branch or not? */ +  if( op == F_BRANCH_WHEN_ZERO ) +  return jz_imm_rel32(0); +  return jnz_imm_rel32(0); +     case F_LOOP:    /* counter in pike_sp-1 */    /* decrement until 0. */    /* if not 0, branch */    /* otherwise, pop */    START_JUMP();    amd64_load_sp_reg();    mov_mem32_reg( sp_reg, -sizeof(struct svalue), REG_RAX );    /* Is it a normal integer? subtype -> 0, type -> PIKE_T_INT */    cmp_reg_imm( REG_RAX, PIKE_T_INT );