2012-06-25
2012-06-25 00:02:25 by Per Hedbor <ph@opera.com>
-
378ad0b57491df502b1bfa6fa1313b9302299b64
(281 lines)
(+258/-23)
[
Show
| Annotate
]
Branch: 7.9
[compiler][amd64] Inline a few mode opcodes
Added inline versions of LTOSVAL2_AND_FREE, LTOSVAL, ASSIGN and
ASSIGN_AND_POP. Slightly optimized BRANCH_WHEN_*ZERO and
BRANCH_WHEN_*LOCAL.
220:
}
}
+ static void and_reg32_imm( enum amd64_reg reg, int imm32 )
+ {
+ rex( 0, 0, 0, reg );
+
+ 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 );
+ }
+ }
+
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 );
272:
}
}
+ static void shl_reg_reg( enum amd64_reg reg, enum amd64_reg sreg)
+ {
+ if( sreg != REG_RCX )
+ Pike_fatal("Not supported\n");
+
+ rex( 1, 0, 0, reg );
+ opcode( 0xd3 );
+ modrm( 3, 4, reg );
+ }
+
+ static void shl_reg32_reg( enum amd64_reg reg, enum amd64_reg sreg)
+ {
+ if( sreg != REG_RCX )
+ Pike_fatal("Not supported\n");
+ rex( 0, 0, 0, reg );
+ opcode( 0xd3 );
+ modrm( 3, 4, reg );
+ }
+
+ static void shl_reg_mem( enum amd64_reg reg, enum amd64_reg mem, int offset)
+ {
+ if( reg == REG_RCX )
+ Pike_fatal("Not supported\n");
+ mov_mem8_reg( mem, offset, REG_RCX );
+ shl_reg_reg( reg, REG_RCX );
+ }
+
static void shr_reg_imm( enum amd64_reg from_reg, int shift )
{
rex( 1, from_reg, 0, 0 );
309:
id( (imm & 0xffffffffLL) );
id( ((imm >> 32)&0xffffffffLL) );
}
+ else if( imm > 0 )
+ {
+ rex(0,0,0,reg);
+ opcode( 0xc7 ); /* mov imm32 -> reg/m 32, SE*/
+ modrm( 3,0,reg );
+ id( (int)imm );
+ }
else
{
rex(1,0,0,reg);
779:
static void jnz( struct label *l ) { return jump_rel8( l, 0x75 ); }
- #define LABELS() struct label label_A, label_B, label_C, label_D;label_A.addr = -1;label_A.n_label_uses = 0;label_B.addr = -1;label_B.n_label_uses = 0;label_C.addr = -1;label_C.n_label_uses = 0;label_D.addr = -1;label_D.n_label_uses = 0;
+ #define LABELS() struct label label_A, label_B, label_C, label_D, label_E;label_A.addr = -1;label_A.n_label_uses = 0;label_B.addr = -1;label_B.n_label_uses = 0;label_C.addr = -1;label_C.n_label_uses = 0;label_D.addr = -1;label_D.n_label_uses = 0;label_E.addr=-1;label_E.n_label_uses=0;
#define LABEL_A label(&label_A)
#define LABEL_B label(&label_B)
#define LABEL_C label(&label_C)
#define LABEL_D label(&label_D)
-
+ #define LABEL_E label(&label_E)
/* Machine code entry prologue.
*
905:
}
/* Note: Uses RAX and RCX internally. reg MUST not be REG_RAX. */
- static void amd64_push_svaluep(int reg)
+ static void amd64_push_svaluep_to(int reg, int spoff)
{
LABELS();
-
+ if( reg == REG_RAX )
+ Pike_fatal("Using RAX in push_svaluep not supported\n" );
amd64_load_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));
+ mov_reg_mem(REG_RAX, sp_reg, spoff*sizeof(struct svalue)+OFFSETOF(svalue, type));
and_reg_imm(REG_RAX, 0x1f);
- mov_reg_mem(REG_RCX, sp_reg, OFFSETOF(svalue, u.refs));
+ mov_reg_mem(REG_RCX, sp_reg, spoff*sizeof(struct svalue)+OFFSETOF(svalue, u.refs));
cmp_reg32_imm(REG_RAX, MAX_REF_TYPE);
jg(&label_A);
- add_imm_mem( 1, REG_RCX,OFFSETOF(pike_string, refs));
+ add_imm_mem( 1, REG_RCX, OFFSETOF(pike_string, refs));
LABEL_A;
-
+ }
+
+ static void amd64_push_svaluep(int reg)
+ {
+ amd64_push_svaluep_to( reg, 0 );
amd64_add_sp( 1 );
}
954:
static void mov_sval_type(enum amd64_reg src, enum amd64_reg dst )
{
mov_mem8_reg( src, OFFSETOF(svalue,type), dst);
- and_reg_imm( dst, 0x1f );
+ and_reg32_imm( dst, 0x1f );
}
1188: Inside #if defined(PIKE_DEBUG)
#ifdef PIKE_DEBUG
static void ins_debug_instr_prologue (PIKE_INSTR_T instr, INT32 arg1, INT32 arg2)
{
+ return;
int flags = instrs[instr].flags;
maybe_update_pc();
1285:
}
}
+ static void amd64_align()
+ {
+ while( PIKE_PC & 7 )
+ ib( 0x90 );
+ }
+
void ins_f_byte(unsigned int b)
{
int flags;
1310:
add_reg_imm_reg(sp_reg, -sizeof(struct svalue), REG_R10 );
amd64_push_svaluep( REG_R10 );
return;
+
#if 0
-
+ case F_ESCAPE_CATCH:
+
case F_EXIT_CATCH:
ins_f_byte( F_ESCAPE_CATCH );
amd64_load_sp_reg();
amd64_push_int( 0, 1 );
return;
#endif
-
+ /* -3 -2 -1 0
+ * lval[0], lval[1], <RANDOM>, **SP**
+ * ->
+ * -4 -3 -2 -1 0
+ * lval[0], lval[1], *lval, <RANDOM>, *SP**
+ *
+ * This will also free *lval iff it has type
+ * array,multiset,mapping or string.
+ */
+ case F_LTOSVAL2_AND_FREE:
+ {
+ amd64_load_sp_reg();
+ mov_mem8_reg( sp_reg, -3*sizeof(struct svalue), REG_RBX );
+ cmp_reg_imm( REG_RBX, T_SVALUE_PTR );
+ jne( &label_A );
+
+ /* inline version for SVALUE_PTR. */
+
+ /* First, make room for the result, move top and inc sp */
+ mov_mem_reg( sp_reg, -sizeof(struct svalue), REG_RAX );
+ mov_mem_reg( sp_reg, -sizeof(struct svalue)+8, REG_RCX );
+ mov_reg_mem( REG_RAX, sp_reg, 0);
+ mov_reg_mem( REG_RCX, sp_reg, 8);
+ amd64_add_sp( 1 );
+
+ mov_mem_reg( sp_reg,
+ -4*sizeof(struct svalue)+OFFSETOF(svalue,u.lval),
+ REG_RBX );
+ amd64_push_svaluep_to(REG_RBX, -2);
+
+ /* Result is now in sp[-2], lval in -4. */
+ /* push svaluep leaves type in RAX */
+ mov_reg_reg( REG_RAX, REG_RCX );
+ /* mov_mem8_reg( sp_reg, -2*sizeof(struct svalue), REG_RCX ); */
+ mov_imm_reg( 1, REG_RAX );
+ shl_reg32_reg( REG_RAX, REG_RCX );
+ and_reg_imm( REG_RAX, (BIT_ARRAY|BIT_MULTISET|BIT_MAPPING|BIT_STRING));
+ jz( &label_B ); /* Do nothing.. */
+
+ /* Free the old value. */
+ amd64_free_svalue( REG_RBX, 0 );
+ /* assign 0 */
+ mov_imm_mem( PIKE_T_INT, REG_RBX, 0 );
+ mov_imm_mem( 0, REG_RBX, 8 );
+ jmp( &label_B ); /* All done */
+
+ LABEL_A;
+ /* So, not a svalueptr. Use C-version */
+ amd64_call_c_opcode( addr, flags );
+ amd64_load_sp_reg();
+ LABEL_B;
+ }
+ return;
+
+ case F_LTOSVAL:
+ {
+ amd64_load_sp_reg();
+ mov_mem8_reg( sp_reg, -sizeof(struct svalue)*2, REG_RAX );
+ /* lval type in RAX. */
+ /*
+ if( rax == T_SVALUE_PTR )
+ push( *l->u.lval )
+
+ possibly:
+ if( rax == T_OBJECT )
+ object_index_no_free( to, lval->u.object, lval->subtype, &lval[1])
+
+ if( rax == T_ARRAY && lval[1].type == PIKE_T_INT )
+ push( l->u.array->item[&lval[1].u.integer] )
+ */
+ cmp_reg_imm( REG_RAX, T_SVALUE_PTR );
+ je( &label_A );
+ /* So, not a svalueptr */
+ mov_reg_reg( sp_reg, ARG1_REG );
+ add_reg_imm_reg( sp_reg, -2*sizeof(struct svalue), ARG2_REG );
+ amd64_call_c_function(lvalue_to_svalue_no_free);
+ amd64_add_sp(1);
+ jmp(&label_B);
+ LABEL_A;
+ mov_mem_reg( sp_reg, -sizeof(struct svalue)*2+OFFSETOF(svalue,u.lval),
+ REG_RCX );
+ amd64_push_svaluep(REG_RCX);
+ LABEL_B;
+ }
+ return;
+ case F_ASSIGN:
+ {
+ amd64_load_sp_reg();
+ mov_mem8_reg( sp_reg, -3*sizeof(struct svalue), REG_RAX );
+ cmp_reg_imm( REG_RAX, T_SVALUE_PTR );
+
+ je( &label_A );
+ /* So, not a svalueptr. Use C-version for simplicity */
+ amd64_call_c_opcode( addr, flags );
+ amd64_load_sp_reg();
+ jmp( &label_B );
+ amd64_align();
+
+ LABEL_A;
+ mov_mem_reg( sp_reg, -3*sizeof(struct svalue)+8, REG_RBX );
+
+ /* Free old value. */
+ amd64_free_svalue( REG_RBX, 0 );
+
+ /* assign new value */
+ /* also move assigned value -> sp[-3] */
+ mov_mem_reg( sp_reg, -sizeof(struct svalue), REG_RAX );
+ mov_mem_reg( sp_reg, -sizeof(struct svalue)+8, REG_RCX );
+ mov_reg_mem( REG_RAX, REG_RBX, 0 );
+ mov_reg_mem( REG_RCX, REG_RBX, 8 );
+ add_reg_imm_reg( sp_reg, -sizeof(struct svalue), REG_RCX );
+ amd64_push_svaluep_to( REG_RCX, -3 );
+ /*
+ Note: For SVALUEPTR we know we do not have to free
+ the lvalue.
+ */
+ amd64_add_sp( -2 );
+ LABEL_B;
+ }
+ return;
+ case F_ASSIGN_AND_POP:
+ {
+ amd64_load_sp_reg();
+ mov_mem8_reg( sp_reg, -3*sizeof(struct svalue), REG_RAX );
+ cmp_reg_imm( REG_RAX, T_SVALUE_PTR );
+
+ je( &label_A );
+ /* So, not a svalueptr. Use C-version for simplicity */
+ amd64_call_c_opcode( addr, flags );
+ amd64_load_sp_reg();
+ jmp( &label_B );
+ amd64_align();
+
+ LABEL_A;
+ mov_mem_reg( sp_reg, -3*sizeof(struct svalue)+8, REG_RBX );
+
+ /* Free old value. */
+ amd64_free_svalue( REG_RBX, 0 );
+
+ /* assign new value */
+ mov_mem_reg( sp_reg, -sizeof(struct svalue), REG_RAX );
+ mov_mem_reg( sp_reg, -sizeof(struct svalue)+8, REG_RCX );
+ mov_reg_mem( REG_RAX, REG_RBX, 0 );
+ mov_reg_mem( REG_RCX, REG_RBX, 8 );
+ /*
+ Note: For SVALUEPTR we know we do not have to free
+ the lvalue.
+ */
+ amd64_add_sp( -3 );
+ LABEL_B;
+ }
+ return;
+ return;
case F_ADD_INTS:
{
amd64_load_sp_reg();
1564:
}
}
- static void ALIGN()
- {
- while( PIKE_PC & 7 )
- ib( 0x90 );
- }
-
+
int amd64_ins_f_jump(unsigned int op, int backward_jump)
{
int flags;
1611:
START_JUMP();
amd64_load_sp_reg();
mov_mem8_reg( sp_reg, -sizeof(struct svalue), REG_RCX );
- cmp_reg32_imm( REG_RCX, PIKE_T_INT );
- je( &label_C );
+ cmp_reg32_imm( REG_RCX, PIKE_T_INT ); je( &label_C );
+ mov_imm_reg( 1, REG_RAX );
+ shl_reg32_reg( REG_RAX, REG_RCX );
+ and_reg32_imm( REG_RAX, BIT_FUNCTION|BIT_OBJECT );
+ jnz( &label_A );
+
+ /* string, array, mapping or float. Always true */
+ amd64_add_sp(-1);
+ amd64_free_svalue_type( sp_reg, REG_RCX, 0 );
+ mov_imm_reg( 1, REG_RBX );
+ jmp( &label_B );
+
LABEL_A;
- /* not an integer. Use svalue_is_true. */
+ /* function or object. Use svalue_is_true. */
add_reg_imm_reg(sp_reg, -sizeof(struct svalue), ARG1_REG );
amd64_call_c_function(svalue_is_true);
mov_reg_reg( REG_RAX, REG_RBX );
- amd64_add_sp( -1 ); /* Pop the stack. */
- amd64_free_svalue( sp_reg, 0 );
+ amd64_add_sp( -1 );
+ amd64_free_svalue( sp_reg, 0 ); /* Pop the stack. */
jmp( &label_B );
LABEL_C;
2159:
*/
mov_sval_type( ARG1_REG, REG_RCX );
cmp_reg32_imm( REG_RCX, PIKE_T_INT ); je( &label_C );
- #if 0
- cmp_reg32_imm( REG_RCX, PIKE_T_OBJECT ); je( &label_A );
- cmp_reg32_imm( REG_RCX, PIKE_T_FUNCTION ); je( &label_A );
+ mov_imm_reg( 1, REG_RAX );
+ shl_reg32_reg( REG_RAX, REG_RCX );
+ and_reg32_imm( REG_RAX, BIT_FUNCTION|BIT_OBJECT );
+ jnz( &label_A );
/* Not object, int or function. Always true. */
-
+
mov_imm_reg( 1, REG_RAX );
jmp( &label_B );
- #endif
+ LABEL_A;
amd64_call_c_function(svalue_is_true);
jmp( &label_B );