up the selector accordingly.
git-svn-id: svn://svn.valgrind.org/vex/trunk@27
struct _IRExpr* addr;
} LDle;
struct {
- struct _IRConst* con;
+ IRConst* con;
} Const;
} Iex;
}
IRNextTag;
typedef
- struct _IRNext {
+ struct {
IRNextTag tag;
union {
struct {
- struct _IRConst* dst;
+ IRConst* dst;
} UJump;
struct {
- struct _IRExpr* cond;
- struct _IRConst* dst0;
- struct _IRConst* dst1;
+ IRExpr* cond;
+ IRConst* dst0;
+ IRConst* dst1;
} CJump01;
struct {
- struct _IRExpr* dst;
+ IRExpr* dst;
} IJump;
} Inx;
}
typedef
enum {
- Xam_IR,
- Xam_IRRS
+ Xam_IR, /* Immediate + Reg */
+ Xam_IRRS /* Immediate + Reg1 + (Reg2 << Shift) */
}
X86AModeTag;
extern void ppX86AMode ( FILE*, X86AMode* );
-/* --------- Operands. Not all are valid for all insns. --------- */
+/* --------- Operand, which can be reg, immediate or memory. --------- */
typedef
enum {
- Xop_Imm,
- Xop_Reg,
- Xop_Mem
+ Xrmi_Imm,
+ Xrmi_Reg,
+ Xrmi_Mem
}
- X86OperandTag;
+ X86RMITag;
typedef
struct {
- X86OperandTag tag;
+ X86RMITag tag;
union {
struct {
UInt imm32;
X86AMode* am;
} Mem;
}
- Xop;
+ Xrmi;
}
- X86Operand;
+ X86RMI;
-extern X86Operand* X86Operand_Imm ( UInt );
-extern X86Operand* X86Operand_Reg ( HReg );
-extern X86Operand* X86Operand_Mem ( X86AMode* );
+extern X86RMI* X86RMI_Imm ( UInt );
+extern X86RMI* X86RMI_Reg ( HReg );
+extern X86RMI* X86RMI_Mem ( X86AMode* );
-extern void ppX86Operand ( FILE*, X86Operand* );
+extern void ppX86RMI ( FILE*, X86RMI* );
+
+
+/* --------- Operand, which can be reg or immediate only. --------- */
+
+typedef
+ enum {
+ Xri_Imm,
+ Xri_Reg
+ }
+ X86RITag;
+
+typedef
+ struct {
+ X86RITag tag;
+ union {
+ struct {
+ UInt imm32;
+ } Imm;
+ struct {
+ HReg reg;
+ } Reg;
+ }
+ Xri;
+ }
+ X86RI;
+
+extern X86RI* X86RI_Imm ( UInt );
+extern X86RI* X86RI_Reg ( HReg );
+
+extern void ppX86RI ( FILE*, X86RI* );
+
+
+/* --------- Operand, which can be reg or memory only. --------- */
+
+typedef
+ enum {
+ Xrm_Reg,
+ Xrm_Mem
+ }
+ X86RMTag;
+
+typedef
+ struct {
+ X86RMTag tag;
+ union {
+ struct {
+ HReg reg;
+ } Reg;
+ struct {
+ X86AMode* am;
+ } Mem;
+ }
+ Xrm;
+ }
+ X86RM;
+
+extern X86RM* X86RM_Reg ( HReg );
+extern X86RM* X86RM_Mem ( X86AMode* );
+
+extern void ppX86RM ( FILE*, X86RM* );
/* --------- Instructions. --------- */
+/* --------- */
typedef
- enum { Xalu_ADD, Xalu_SUB, Xalu_ADC, Xalu_SBB, Xalu_AND, Xalu_OR, Xalu_XOR }
+ enum {
+ Xalu_MOV,
+ Xalu_ADD, Xalu_SUB, Xalu_ADC, Xalu_SBB,
+ Xalu_AND, Xalu_OR, Xalu_XOR
+ }
X86AluOp;
extern void ppX86AluOp ( FILE*, X86AluOp );
+/* --------- */
+typedef
+ enum {
+ Xsh_SHL, Xsh_SHR, Xsh_SAR,
+ Xsh_ROL, Xsh_ROR
+ }
+ X86ShiftOp;
+
+extern void ppX86ShiftOp ( FILE*, X86ShiftOp );
+
+
+/* --------- */
typedef
enum {
- Xin_LD32, /* 32-bit integer load */
- Xin_ST32, /* 32-bit integer store */
- Xin_Alu32, /* 32-bit arith/logical, R-R, R-M, M-R */
- Xin_Mov32, /* 32-bit move R-R R-M M-R I-R I-M */
- Xin_Alu16 /* 16-bit arith/logical, R-R, R-M, M-R */
+ Xin_Alu32R, /* 32-bit mov/arith/logical, dst=REG */
+ Xin_Alu32M, /* 32-bit mov/arith/logical, dst=MEM */
+ Xin_Sh32, /* 32-bit shift/rotate, dst=REG or MEM */
+ Xin_RET
}
X86InstrTag;
struct {
X86InstrTag tag;
union {
- struct {
- HReg src;
- X86AMode* dst;
- } ST32;
- struct {
- X86AMode* src;
- HReg dst;
- } LD32;
struct {
- X86AluOp op;
- X86Operand* src;
- X86Operand* dst;
- } Alu32;
+ X86AluOp op;
+ X86RMI* src;
+ HReg dst;
+ } Alu32R;
struct {
- X86Operand* src;
- X86Operand* dst;
- } Mov32;
+ X86AluOp op;
+ X86RI* src;
+ X86AMode* dst;
+ } Alu32M;
struct {
- X86AluOp op;
- X86Operand* src;
- X86Operand* dst;
- } Alu16;
+ X86ShiftOp op;
+ UInt src; /* shift amount, or 0 means %cl */
+ X86RM* dst;
+ } Sh32;
+ struct {
+ } RET;
} Xin;
}
X86Instr;
-extern X86Instr* X86Instr_ST32 ( HReg, X86AMode* );
-extern X86Instr* X86Instr_LD32 ( X86AMode*, HReg );
-extern X86Instr* X86Instr_Alu32 ( X86AluOp, X86Operand*, X86Operand* );
-extern X86Instr* X86Instr_Mov32 ( X86Operand*, X86Operand* );
-extern X86Instr* X86Instr_Alu16 ( X86AluOp, X86Operand*, X86Operand* );
+extern X86Instr* X86Instr_Alu32R ( X86AluOp, X86RMI*, HReg );
+extern X86Instr* X86Instr_Alu32M ( X86AluOp, X86RI*, X86AMode* );
+extern X86Instr* X86Instr_Sh32 ( X86ShiftOp, UInt, X86RM* );
+extern X86Instr* X86Instr_RET ( void );
extern void ppX86Instr ( FILE*, X86Instr* );
/*--- ISEL: Integer expressions ---*/
/*---------------------------------------------------------*/
+/* forwards ... */
+static X86RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e );
+
+
+static X86Instr* mk_MOV_RR ( HReg src, HReg dst )
+{
+ assert(hregClass(src) == HRcInt);
+ assert(hregClass(dst) == HRcInt);
+ return X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(src), dst);
+}
+
+
/* Select insns for an integer-typed expression, and add them to the
code list. Return a vreg holding the result. The vreg MUST NOT BE
MODIFIED. If you want to modify it, ask for a new vreg, copy it in
best to map both vregs to the same real register, so the copies
will often disappear later in the game.
*/
-HReg iselExprI ( ISelEnv* env, IRExpr* e )
+static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
{
assert(e);
assert(typeOfIRExpr(env->type_env,e) == Ity_I32);
return lookupIRTemp(env, e->Iex.Tmp.tmp);
case Iex_Binop:
- /* Add32(x,y) */
+ /* Add32(x,y). For commutative ops we assume any literal
+ values are on the second operand. */
if (e->Iex.Binop.op == Iop_Add32) {
- HReg res = newVRegI(env);
- HReg src = iselExprI(env, e->Iex.Binop.arg1);
- HReg dst = iselExprI(env, e->Iex.Binop.arg2);
- addInstr(env, X86Instr_Mov32(
- X86Operand_Reg(dst),
- X86Operand_Reg(res)));
- addInstr(env, X86Instr_Alu32(
- Xalu_ADD, X86Operand_Reg(src),
- X86Operand_Reg(res)) );
- return res;
+ HReg dst = newVRegI(env);
+ HReg reg = iselIntExpr_R(env, e->Iex.Binop.arg1);
+ X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
+ addInstr(env, mk_MOV_RR(reg,dst));
+ addInstr(env, X86Instr_Alu32R(Xalu_ADD, rmi, dst));
+ return dst;
}
+#if 0
/* 32-bit literals */
case Iex_Const: {
switch (e->Iex.Const.con->tag) {
default: break;
}
}
+#endif
default:
break;
}
-/* Similarly, return an AMode which computes the value of the
- specified expression, possibly also adding insns to the code list
- as a result.
+/*---------------------------------------------------------*/
+/*--- ISEL: Integer expression auxiliaries ---*/
+/*---------------------------------------------------------*/
+
+/* Return an AMode which computes the value of the specified
+ expression, possibly also adding insns to the code list as a
+ result.
*/
-X86AMode* iselAMode ( ISelEnv* env, IRExpr* e )
+static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e )
{
assert(e);
assert(typeOfIRExpr(env->type_env,e) == Ity_I32);
&& e->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
UInt shift = e->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
if (shift == 2 || shift == 4 || shift == 8) {
- HReg r1 = iselExprI(env, e->Iex.Binop.arg1);
- HReg r2 = iselExprI(env, e->Iex.Binop.arg2->Iex.Binop.arg1 );
+ HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
+ HReg r2 = iselIntExpr_R(env, e->Iex.Binop.arg2->Iex.Binop.arg1 );
return X86AMode_IRRS(0, r1, r2, shift);
}
}
&& e->Iex.Binop.op == Iop_Add32
&& e->Iex.Binop.arg2->tag == Iex_Const
&& e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
- HReg r1 = iselExprI(env, e->Iex.Binop.arg1);
+ HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
return X86AMode_IR(r1, e->Iex.Binop.arg2->Iex.Const.con->Ico.U32);
}
/* Doesn't match anything in particular. Generate it into
a register and use that. */
{
- HReg r1 = iselExprI(env, e);
+ HReg r1 = iselIntExpr_R(env, e);
return X86AMode_IR(r1, 0);
}
}
+/* Similarly, calculate an expression into an X86RMI operand. */
+
+static X86RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e )
+{
+ assert(e);
+ assert(typeOfIRExpr(env->type_env,e) == Ity_I32);
+
+ /* special case: immediate */
+ if (e->tag == Iex_Const
+ && e->Iex.Const.con->tag == Ico_U32) {
+ return X86RMI_Imm(e->Iex.Const.con->Ico.U32);
+ }
+
+ /* special case: load from memory */
+
+ /* default case: calculate into a register and return that */
+ {
+ HReg r = iselIntExpr_R ( env, e );
+ return X86RMI_Reg(r);
+ }
+}
+
+
+/* Calculate an expression into an X86RI operand. */
+
+static X86RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e )
+{
+ assert(e);
+ assert(typeOfIRExpr(env->type_env,e) == Ity_I32);
+
+ /* special case: immediate */
+ if (e->tag == Iex_Const
+ && e->Iex.Const.con->tag == Ico_U32) {
+ return X86RI_Imm(e->Iex.Const.con->Ico.U32);
+ }
+
+ /* default case: calculate into a register and return that */
+ {
+ HReg r = iselIntExpr_R ( env, e );
+ return X86RI_Reg(r);
+ }
+}
+
+
/*---------------------------------------------------------*/
/*--- ISEL: Statements ---*/
/*---------------------------------------------------------*/
void iselStmt ( ISelEnv* env, IRStmt* stmt )
{
+ fprintf(stdout, "-- ");
+ ppIRStmt(stdout, stmt);
+ fprintf(stdout, "\n");
+
switch (stmt->tag) {
case Ist_Put:
if (stmt->Ist.Put.size == 4) {
- HReg ebp = mkHReg(5, HRcInt, False);
- HReg reg = iselExprI(env, stmt->Ist.Put.expr);
+ /* We're going to write to memory, so compute the
+ RHS into an X86RI. */
+ HReg ebp = mkHReg(5, HRcInt, False);
+ X86RI* ri = iselIntExpr_RI(env, stmt->Ist.Put.expr);
addInstr(env,
- X86Instr_ST32(reg,
- X86AMode_IR(stmt->Ist.Put.offset,
- ebp)
- ));
+ X86Instr_Alu32M(
+ Xalu_MOV,
+ ri,
+ X86AMode_IR(stmt->Ist.Put.offset,ebp)
+ ));
return;
}
void iselNext ( ISelEnv* env, IRNext* next )
{
+ fprintf(stdout, "-- ");
+ ppIRNext(stdout, next);
+ fprintf(stdout, "\n");
+
switch (next->tag) {
- default:
+ case Inx_UJump: {
+ HReg eax = mkHReg(0, HRcInt, False);
+ assert(next->Inx.UJump.dst->tag == Ico_U32);
+ addInstr(env, X86Instr_Alu32R(
+ Xalu_MOV,
+ X86RMI_Imm(next->Inx.UJump.dst->Ico.U32),
+ eax));
+ addInstr(env, X86Instr_RET());
+ return;
+ }
+ default:
ppIRNext(stderr, next);
panic("iselNext");
}
}
env->vregmap[i].vreg = hreg;
}
+ env->ctr = 100; //env->n_vregmap;
/* Ok, finally we can iterate over the statements. */
for (stmt = bb->stmts; stmt; stmt=stmt->link)
}
-/* --------- X86Operand. Not all are valid for all insns. --------- */
+/* --------- Operand, which can be reg, immediate or memory. --------- */
-X86Operand* X86Operand_Imm ( UInt imm32 ) {
- X86Operand* op = malloc(sizeof(X86Operand));
- op->tag = Xop_Imm;
- op->Xop.Imm.imm32 = imm32;
+X86RMI* X86RMI_Imm ( UInt imm32 ) {
+ X86RMI* op = malloc(sizeof(X86RMI));
+ op->tag = Xrmi_Imm;
+ op->Xrmi.Imm.imm32 = imm32;
return op;
}
-X86Operand* X86Operand_Reg ( HReg reg ) {
- X86Operand* op = malloc(sizeof(X86Operand));
- op->tag = Xop_Reg;
- op->Xop.Reg.reg = reg;
+X86RMI* X86RMI_Reg ( HReg reg ) {
+ X86RMI* op = malloc(sizeof(X86RMI));
+ op->tag = Xrmi_Reg;
+ op->Xrmi.Reg.reg = reg;
return op;
}
-X86Operand* X86Operand_Mem ( X86AMode* am ) {
- X86Operand* op = malloc(sizeof(X86Operand));
- op->tag = Xop_Mem;
- op->Xop.Mem.am = am;
+X86RMI* X86RMI_Mem ( X86AMode* am ) {
+ X86RMI* op = malloc(sizeof(X86RMI));
+ op->tag = Xrmi_Mem;
+ op->Xrmi.Mem.am = am;
return op;
}
-void ppX86Operand ( FILE* f, X86Operand* op ) {
+void ppX86RMI ( FILE* f, X86RMI* op ) {
switch (op->tag) {
- case Xop_Imm:
- fprintf(f, "$0x%x", op->Xop.Imm.imm32);
+ case Xrmi_Imm:
+ fprintf(f, "$0x%x", op->Xrmi.Imm.imm32);
return;
- case Xop_Reg:
- ppHRegX86(f, op->Xop.Reg.reg);
+ case Xrmi_Reg:
+ ppHRegX86(f, op->Xrmi.Reg.reg);
return;
- case Xop_Mem:
- ppX86AMode(f, op->Xop.Mem.am);
+ case Xrmi_Mem:
+ ppX86AMode(f, op->Xrmi.Mem.am);
return;
default:
- panic("ppX86Operand");
+ panic("ppX86RMI");
+ }
+}
+
+
+/* --------- Operand, which can be reg or immediate only. --------- */
+
+X86RI* X86RI_Imm ( UInt imm32 ) {
+ X86RI* op = malloc(sizeof(X86RI));
+ op->tag = Xri_Imm;
+ op->Xri.Imm.imm32 = imm32;
+ return op;
+}
+
+X86RI* X86RI_Reg ( HReg reg ) {
+ X86RI* op = malloc(sizeof(X86RI));
+ op->tag = Xri_Reg;
+ op->Xri.Reg.reg = reg;
+ return op;
+}
+
+void ppX86RI ( FILE* f, X86RI* op ) {
+ switch (op->tag) {
+ case Xri_Imm:
+ fprintf(f, "$0x%x", op->Xri.Imm.imm32);
+ return;
+ case Xri_Reg:
+ ppHRegX86(f, op->Xri.Reg.reg);
+ return;
+ default:
+ panic("ppX86RI");
+ }
+}
+
+
+/* --------- Operand, which can be reg or memory only. --------- */
+
+X86RM* X86RM_Reg ( HReg reg ) {
+ X86RM* op = malloc(sizeof(X86RM));
+ op->tag = Xrm_Reg;
+ op->Xrm.Reg.reg = reg;
+ return op;
+}
+
+X86RM* X86RM_Mem ( X86AMode* am ) {
+ X86RM* op = malloc(sizeof(X86RM));
+ op->tag = Xrm_Mem;
+ op->Xrm.Mem.am = am;
+ return op;
+}
+
+void ppX86RM ( FILE* f, X86RM* op ) {
+ switch (op->tag) {
+ case Xrm_Mem:
+ ppX86AMode(f, op->Xrm.Mem.am);
+ return;
+ case Xrm_Reg:
+ ppHRegX86(f, op->Xrm.Reg.reg);
+ return;
+ default:
+ panic("ppX86RM");
}
}
void ppX86AluOp ( FILE* f, X86AluOp op ) {
Char* name;
switch (op) {
+ case Xalu_MOV: name = "mov"; break;
case Xalu_ADD: name = "add"; break;
case Xalu_SUB: name = "sub"; break;
case Xalu_ADC: name = "adc"; break;
fprintf(f, "%s", name);
}
-X86Instr* X86Instr_ST32 ( HReg src, X86AMode* dst ) {
- X86Instr* i = malloc(sizeof(X86Instr));
- i->tag = Xin_ST32;
- i->Xin.ST32.src = src;
- i->Xin.ST32.dst = dst;
- return i;
+void ppX86ShiftOp ( FILE* f, X86ShiftOp op ) {
+ Char* name;
+ switch (op) {
+ case Xsh_SHL: name = "shl"; break;
+ case Xsh_SHR: name = "shr"; break;
+ case Xsh_SAR: name = "sar"; break;
+ case Xsh_ROL: name = "rol"; break;
+ case Xsh_ROR: name = "ror"; break;
+ default: panic("ppX86ShiftOp");
+ }
+ fprintf(f, "%s", name);
}
-X86Instr* X86Instr_LD32 ( X86AMode* src, HReg dst ) {
- X86Instr* i = malloc(sizeof(X86Instr));
- i->tag = Xin_LD32;
- i->Xin.LD32.src = src;
- i->Xin.LD32.dst = dst;
+X86Instr* X86Instr_Alu32R ( X86AluOp op, X86RMI* src, HReg dst ) {
+ X86Instr* i = malloc(sizeof(X86Instr));
+ i->tag = Xin_Alu32R;
+ i->Xin.Alu32R.op = op;
+ i->Xin.Alu32R.src = src;
+ i->Xin.Alu32R.dst = dst;
return i;
}
-X86Instr* X86Instr_Alu32 ( X86AluOp op, X86Operand* src, X86Operand* dst ) {
- X86Instr* i = malloc(sizeof(X86Instr));
- i->tag = Xin_Alu32;
- i->Xin.Alu32.op = op;
- i->Xin.Alu32.src = src;
- i->Xin.Alu32.dst = dst;
+X86Instr* X86Instr_Alu32M ( X86AluOp op, X86RI* src, X86AMode* dst ) {
+ X86Instr* i = malloc(sizeof(X86Instr));
+ i->tag = Xin_Alu32M;
+ i->Xin.Alu32M.op = op;
+ i->Xin.Alu32M.src = src;
+ i->Xin.Alu32M.dst = dst;
return i;
}
-X86Instr* X86Instr_Mov32 ( X86Operand* src, X86Operand* dst ) {
- X86Instr* i = malloc(sizeof(X86Instr));
- i->tag = Xin_Mov32;
- i->Xin.Mov32.src = src;
- i->Xin.Mov32.dst = dst;
+X86Instr* X86Instr_Sh32 ( X86ShiftOp op, UInt src, X86RM* dst ) {
+ X86Instr* i = malloc(sizeof(X86Instr));
+ i->tag = Xin_Sh32;
+ i->Xin.Sh32.op = op;
+ i->Xin.Sh32.src = src;
+ i->Xin.Sh32.dst = dst;
return i;
}
-X86Instr* X86Instr_Alu16 ( X86AluOp op, X86Operand* src, X86Operand* dst ) {
- X86Instr* i = malloc(sizeof(X86Instr));
- i->tag = Xin_Alu16;
- i->Xin.Alu16.op = op;
- i->Xin.Alu16.src = src;
- i->Xin.Alu16.dst = dst;
+X86Instr* X86Instr_RET ( void ) {
+ X86Instr* i = malloc(sizeof(X86Instr));
+ i->tag = Xin_RET;
return i;
}
+
void ppX86Instr ( FILE* f, X86Instr* i ) {
switch (i->tag) {
- case Xin_ST32:
- fprintf(f, "movl ");
- ppHRegX86(f, i->Xin.ST32.src);
- fprintf(f, ",");
- ppX86AMode(f, i->Xin.ST32.dst);
- return;
- case Xin_LD32:
- fprintf(f, "movl ");
- ppX86AMode(f, i->Xin.LD32.src);
+ case Xin_Alu32R:
+ ppX86AluOp(f, i->Xin.Alu32R.op);
+ fprintf(f, "l ");
+ ppX86RMI(f, i->Xin.Alu32R.src);
fprintf(f, ",");
- ppHRegX86(f, i->Xin.LD32.dst);
+ ppHRegX86(f, i->Xin.Alu32R.dst);
return;
- case Xin_Alu32:
- ppX86AluOp(f, i->Xin.Alu32.op);
+ case Xin_Alu32M:
+ ppX86AluOp(f, i->Xin.Alu32M.op);
fprintf(f, "l ");
- ppX86Operand(f, i->Xin.Alu32.src);
+ ppX86RI(f, i->Xin.Alu32M.src);
fprintf(f, ",");
- ppX86Operand(f, i->Xin.Alu32.dst);
+ ppX86AMode(f, i->Xin.Alu32M.dst);
return;
- case Xin_Mov32:
- fprintf(f, "movl ");
- ppX86Operand(f, i->Xin.Mov32.src);
- fprintf(f, ",");
- ppX86Operand(f, i->Xin.Mov32.dst);
+ case Xin_Sh32:
+ ppX86ShiftOp(f, i->Xin.Sh32.op);
+ fprintf(f, "l ");
+ if (i->Xin.Sh32.src == 0)
+ fprintf(f, " %%cl,");
+ else
+ fprintf(f, " $%d,", i->Xin.Sh32.src);
+ ppX86RM(f, i->Xin.Sh32.dst);
return;
- case Xin_Alu16:
- ppX86AluOp(f, i->Xin.Alu16.op);
- fprintf(f, "w ");
- ppX86Operand(f, i->Xin.Alu16.src);
- fprintf(f, ",");
- ppX86Operand(f, i->Xin.Alu16.dst);
+ case Xin_RET:
+ fprintf(f, "ret");
return;
default:
panic("ppX86Instr");