From: Julian Seward Date: Tue, 17 Aug 2004 23:59:23 +0000 (+0000) Subject: iropt: implement flattening (into SSA form). This caused various X-Git-Tag: svn/VALGRIND_3_0_1^2~1161 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1c26f704488f4e6a103a8c6183f514fdff91b91a;p=thirdparty%2Fvalgrind.git iropt: implement flattening (into SSA form). This caused various primops to become exposed when previously they were treated as part of a pattern, hence the changes to host-x86/*.c to handle them. git-svn-id: svn://svn.valgrind.org/vex/trunk@173 --- diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 6848a29b00..2e4a6543d3 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -47,26 +47,14 @@ static UChar* guest_code; /* CONST */ static Addr32 guest_eip; -/* The BBIR* into which we're generating code. */ -/* What it points to changes as we work through the bb. */ +/* The IRBB* into which we're generating code. */ static IRBB* irbb; -/* Points to the last stmt added to the statement list of irbb, so - that when a new stmt is added, the .link field can be correctly - updated. */ -static IRStmt* last_stmt; - /* Add a statement to the list held by "irbb". */ -static void stmt ( IRStmt* stmt ) +static void stmt ( IRStmt* st ) { - stmt->link = NULL; - if (irbb->stmts == NULL) { - irbb->stmts = stmt; - } else { - last_stmt->link = stmt; - } - last_stmt = stmt; + addStmtToIRBB( irbb, st ); } /* Generate a new temporary of the given type. */ @@ -4970,7 +4958,7 @@ static UInt disInstr ( UInt delta, Bool* isEnd ) UChar sorb = 0; /* For printing the stmts after each insn. */ - IRStmt* first_stmt = last_stmt; + Int first_stmt_idx = irbb->stmts_used; *isEnd = False; addr = t1 = t2 = INVALID_IRTEMP; @@ -8437,21 +8425,14 @@ static UInt disInstr ( UInt delta, Bool* isEnd ) decode_success: /* All decode successes end up here. */ DIP("\n"); - if (first_stmt == NULL) - first_stmt = irbb->stmts; - else - first_stmt = first_stmt->link; - while (True) { - if (!first_stmt) - break; - if (print_codegen) { - vex_printf(" "); - ppIRStmt(first_stmt); - vex_printf("\n"); - } - if (first_stmt == last_stmt) - break; - first_stmt = first_stmt->link; + { Int i; + for (i = first_stmt_idx; i < irbb->stmts_used; i++) { + if (print_codegen) { + vex_printf(" "); + ppIRStmt(irbb->stmts[i]); + vex_printf("\n"); + } + } } if (*isEnd) { vassert(irbb->next != NULL); @@ -8494,8 +8475,7 @@ IRBB* bbToIR_X86Instr ( UChar* x86code, print_codegen = (vex_verbosity >= 1); guest_code = x86code; guest_eip = (Addr32)eip; - irbb = mkIRBB( newIRTypeEnv(), NULL, NULL, Ijk_Boring ); - last_stmt = NULL; + irbb = emptyIRBB(); vassert((eip >> 32) == 0); vassert(vex_guest_insns_per_bb >= 1); diff --git a/VEX/priv/host-x86/hdefs.c b/VEX/priv/host-x86/hdefs.c index 451bf9bff6..ccc6b5f32f 100644 --- a/VEX/priv/host-x86/hdefs.c +++ b/VEX/priv/host-x86/hdefs.c @@ -537,6 +537,13 @@ X86Instr* X86Instr_Store ( UChar sz, HReg src, X86AMode* dst ) { vassert(sz == 1 || sz == 2); return i; } +X86Instr* X86Instr_Set32 ( X86CondCode cond, HReg dst ) { + X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); + i->tag = Xin_Set32; + i->Xin.Set32.cond = cond; + i->Xin.Set32.dst = dst; + return i; +} X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst ) { X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); i->tag = Xin_FpUnary; @@ -675,6 +682,10 @@ void ppX86Instr ( X86Instr* i ) { vex_printf(","); ppX86AMode(i->Xin.Store.dst); return; + case Xin_Set32: + vex_printf("setl%s ", showX86CondCode(i->Xin.Set32.cond)); + ppHRegX86(i->Xin.Set32.dst); + return; case Xin_FpUnary: vex_printf("g%sD ", showX86FpOp(i->Xin.FpUnary.op)); ppHRegX86(i->Xin.FpUnary.src); @@ -800,6 +811,9 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i) addHRegUse(u, HRmRead, i->Xin.Store.src); addRegUsage_X86AMode(u, i->Xin.Store.dst); return; + case Xin_Set32: + addHRegUse(u, HRmWrite, i->Xin.Set32.dst); + return; case Xin_FpUnary: addHRegUse(u, HRmRead, i->Xin.FpUnary.src); addHRegUse(u, HRmWrite, i->Xin.FpUnary.dst); @@ -887,6 +901,9 @@ void mapRegs_X86Instr (HRegRemap* m, X86Instr* i) mapReg(m, &i->Xin.Store.src); mapRegs_X86AMode(m, i->Xin.Store.dst); return; + case Xin_Set32: + mapReg(m, &i->Xin.Set32.dst); + return; case Xin_FpBinary: mapReg(m, &i->Xin.FpBinary.srcL); mapReg(m, &i->Xin.FpBinary.srcR); @@ -1425,6 +1442,9 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) *p++ = 0x68; p = emit32(p, i->Xin.Push.src->Xrmi.Imm.imm32); goto done; + case Xrmi_Reg: + *p++ = 0x50 + iregNo(i->Xin.Push.src->Xrmi.Reg.reg); + goto done; default: goto bad; } @@ -1550,6 +1570,36 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) } break; + case Xin_Set32: + /* Make the destination register be 1 or 0, depending on whether + the relevant condition holds. We have to dodge and weave + when the destination is %esi or %edi as we cannot directly + emit the native 'setb %reg' for those. Further complication: + the top 24 bits of the destination should be forced to zero, + but doing 'xor %r,%r' kills the flag(s) we are about to read. + Sigh. */ + /* First: movl $0, %dst */ + *p++ = 0xB8 + iregNo(i->Xin.Set32.dst); + p = emit32(p, 0); + /* Do we need to swap in %eax? */ + + if (iregNo(i->Xin.Set32.dst) >= 4) { + /* xchg %eax, %dst */ + *p++ = 0x90 + iregNo(i->Xin.Set32.dst); + /* setb lo8(%reg) */ + *p++ = 0x0F; + *p++ = 0x90 + (UChar)(i->Xin.Set32.cond); + p = doAMode_R(p, fake(0), hregX86_EAX()); + /* xchg %eax, %dst */ + *p++ = 0x90 + iregNo(i->Xin.Set32.dst); + } else { + /* setb lo8(%reg) */ + *p++ = 0x0F; + *p++ = 0x90 + (UChar)(i->Xin.Set32.cond); + p = doAMode_R(p, fake(0), i->Xin.Set32.dst); + } + goto done; + case Xin_Store: if (i->Xin.Store.sz == 2) { /* This case, at least, is simple, given that we can @@ -1652,13 +1702,13 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) /* ffree %st(7) */ p = do_ffree_st7(p); /* pushl %hi ; pushl %lo */ - *p++ = 0x50 + hregNumber(i->Xin.FpI64.iregHi); - *p++ = 0x50 + hregNumber(i->Xin.FpI64.iregLo); + *p++ = 0x50 + iregNo(i->Xin.FpI64.iregHi); + *p++ = 0x50 + iregNo(i->Xin.FpI64.iregLo); /* fildll 0(%esp) */ *p++ = 0xDF; *p++ = 0x6C; *p++ = 0x24; *p++ = 0x00; /* addl $8, %esp */ *p++ = 0x83; *p++ = 0xC4; *p++ = 0x08; - p = do_fstp_st(p, 1+hregNumber(i->Xin.FpI64.freg)); + p = do_fstp_st(p, 1+iregNo(i->Xin.FpI64.freg)); goto done; } diff --git a/VEX/priv/host-x86/hdefs.h b/VEX/priv/host-x86/hdefs.h index 5e698f703f..b77e30d9c9 100644 --- a/VEX/priv/host-x86/hdefs.h +++ b/VEX/priv/host-x86/hdefs.h @@ -273,6 +273,7 @@ typedef Xin_CMov32, /* conditional move */ Xin_LoadEX, /* mov{s,z}{b,w}l from mem to reg */ Xin_Store, /* store 16/8 bit value in memory */ + Xin_Set32, /* convert condition code to 32-bit value */ Xin_FpUnary, /* FP fake unary op */ Xin_FpBinary, /* FP fake binary op */ Xin_FpLdSt, /* FP fake load/store */ @@ -366,6 +367,11 @@ typedef HReg src; X86AMode* dst; } Store; + /* Convert a x86 condition code to a 32-bit value (0 or 1). */ + struct { + X86CondCode cond; + HReg dst; + } Set32; /* X86 Floating point (fake 3-operand, "flat reg file" insns) */ struct { X86FpOp op; @@ -409,6 +415,7 @@ extern X86Instr* X86Instr_CMov32 ( X86CondCode, X86RM* src, HReg dst ); extern X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned, X86AMode* src, HReg dst ); extern X86Instr* X86Instr_Store ( UChar sz, HReg src, X86AMode* dst ); +extern X86Instr* X86Instr_Set32 ( X86CondCode cond, HReg dst ); extern X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst ); extern X86Instr* X86Instr_FpBinary ( X86FpOp op, HReg srcL, HReg srcR, HReg dst ); extern X86Instr* X86Instr_FpLdSt ( Bool isLoad, UChar sz, HReg reg, X86AMode* ); diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index a653da2071..1dca90d499 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -230,6 +230,7 @@ static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e ); static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e ); static void iselIntExpr64 ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e ); +static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e ); static X86Instr* mk_MOVsd_RR ( HReg src, HReg dst ) @@ -487,6 +488,12 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e ) addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, X86RM_Reg(dst))); return dst; } + case Iop_1Uto8: { + HReg dst = newVRegI(env); + X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg); + addInstr(env, X86Instr_Set32(cond,dst)); + return dst; + } case Iop_16to8: case Iop_32to8: case Iop_32to16: @@ -776,6 +783,15 @@ static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e ) return Xcc_Z; } + /* var */ + if (e->tag == Iex_Tmp) { + HReg r32 = lookupIRTemp(env, e->Iex.Tmp.tmp); + HReg dst = newVRegI(env); + addInstr(env, mk_MOVsd_RR(r32,dst)); + addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(1),dst)); + return Xcc_NZ; + } + ppIRExpr(e); vpanic("iselCondCode"); } @@ -1145,6 +1161,12 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) addInstr(env, mk_MOVsd_RR(rLo,dstLo) ); return; } + if (ty == Ity_Bit) { + X86CondCode cond = iselCondCode(env, stmt->Ist.Tmp.expr); + HReg dst = lookupIRTemp(env, tmp); + addInstr(env, X86Instr_Set32(cond, dst)); + return; + } if (ty == Ity_F64) { HReg dst = lookupIRTemp(env, tmp); HReg src = iselDblExpr(env, stmt->Ist.Tmp.expr); @@ -1202,7 +1224,6 @@ HInstrArray* iselBB_X86 ( IRBB* bb, Addr64(*find_helper)(Char*) ) { Int i, j; HReg hreg, hregHI; - IRStmt* stmt; /* Make up an initial environment to use. */ ISelEnv* env = LibVEX_Alloc(sizeof(ISelEnv)); @@ -1245,8 +1266,8 @@ HInstrArray* iselBB_X86 ( IRBB* bb, Addr64(*find_helper)(Char*) ) env->vreg_ctr = j; /* Ok, finally we can iterate over the statements. */ - for (stmt = bb->stmts; stmt; stmt=stmt->link) - iselStmt(env,stmt); + for (i = 0; i < bb->stmts_used; i++) + iselStmt(env,bb->stmts[i]); iselNext(env,bb->next,bb->jumpkind); diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index f6862ff040..7415517d22 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -269,15 +269,17 @@ void ppIRTypeEnv ( IRTypeEnv* env ) { } + + void ppIRBB ( IRBB* bb ) { - IRStmt* s; + Int i; vex_printf("IRBB {\n"); ppIRTypeEnv(bb->tyenv); vex_printf("\n"); - for (s = bb->stmts; s; s = s->link) { + for (i = 0; i < bb->stmts_used; i++) { vex_printf( " "); - ppIRStmt(s); + ppIRStmt(bb->stmts[i]); vex_printf( "\n"); } vex_printf( " goto {"); @@ -413,7 +415,6 @@ IRExpr* IRExpr_Mux0X ( IRExpr* cond, IRExpr* expr0, IRExpr* exprX ) { IRStmt* IRStmt_Put ( Int off, IRExpr* value ) { IRStmt* s = LibVEX_Alloc(sizeof(IRStmt)); s->tag = Ist_Put; - s->link = NULL; s->Ist.Put.offset = off; s->Ist.Put.expr = value; return s; @@ -422,7 +423,6 @@ IRStmt* IRStmt_PutI ( IRExpr* off, IRExpr* value, UShort minoff, UShort maxoff ) { IRStmt* s = LibVEX_Alloc(sizeof(IRStmt)); s->tag = Ist_PutI; - s->link = NULL; s->Ist.PutI.offset = off; s->Ist.PutI.expr = value; s->Ist.PutI.minoff = minoff; @@ -432,7 +432,6 @@ IRStmt* IRStmt_PutI ( IRExpr* off, IRExpr* value, IRStmt* IRStmt_Tmp ( IRTemp tmp, IRExpr* expr ) { IRStmt* s = LibVEX_Alloc(sizeof(IRStmt)); s->tag = Ist_Tmp; - s->link = NULL; s->Ist.Tmp.tmp = tmp; s->Ist.Tmp.expr = expr; return s; @@ -440,7 +439,6 @@ IRStmt* IRStmt_Tmp ( IRTemp tmp, IRExpr* expr ) { IRStmt* IRStmt_STle ( IRExpr* addr, IRExpr* value ) { IRStmt* s = LibVEX_Alloc(sizeof(IRStmt)); s->tag = Ist_STle; - s->link = NULL; s->Ist.STle.addr = addr; s->Ist.STle.data = value; return s; @@ -448,24 +446,40 @@ IRStmt* IRStmt_STle ( IRExpr* addr, IRExpr* value ) { IRStmt* IRStmt_Exit ( IRExpr* cond, IRConst* dst ) { IRStmt* s = LibVEX_Alloc(sizeof(IRStmt)); s->tag = Ist_Exit; - s->link = NULL; s->Ist.Exit.cond = cond; s->Ist.Exit.dst = dst; return s; } -/* Constructors -- IRBB */ +/* Constructors -- IRBB (sort of) */ -IRBB* mkIRBB ( IRTypeEnv* env, IRStmt* stmts, - IRExpr* next, IRJumpKind jumpkind ) { - IRBB* bb = LibVEX_Alloc(sizeof(IRBB)); - bb->tyenv = env; - bb->stmts = stmts; - bb->next = next; - bb->jumpkind = jumpkind; +IRBB* emptyIRBB ( void ) +{ + IRBB* bb = LibVEX_Alloc(sizeof(IRBB)); + bb->tyenv = emptyIRTypeEnv(); + bb->stmts_used = 0; + bb->stmts_size = 8; + bb->stmts = LibVEX_Alloc(bb->stmts_size * sizeof(IRStmt*)); + bb->next = NULL; + bb->jumpkind = Ijk_Boring; return bb; } +void addStmtToIRBB ( IRBB* bb, IRStmt* st ) +{ + Int i; + if (bb->stmts_used == bb->stmts_size) { + IRStmt** stmts2 = LibVEX_Alloc(2 * bb->stmts_size * sizeof(IRStmt*)); + for (i = 0; i < bb->stmts_size; i++) + stmts2[i] = bb->stmts[i]; + bb->stmts = stmts2; + bb->stmts_size *= 2; + } + vassert(bb->stmts_used < bb->stmts_size); + bb->stmts[bb->stmts_used] = st; + bb->stmts_used++; +} + /*---------------------------------------------------------------*/ /*--- Primop types ---*/ @@ -578,10 +592,12 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) /*---------------------------------------------------------------*/ -/*--- Helper functions for the IR ---*/ +/*--- Helper functions for the IR -- IR Type Environments ---*/ /*---------------------------------------------------------------*/ -IRTypeEnv* newIRTypeEnv ( void ) +/* Make a new, empty IRTypeEnv. */ + +IRTypeEnv* emptyIRTypeEnv ( void ) { IRTypeEnv* env = LibVEX_Alloc(sizeof(IRTypeEnv)); env->types = LibVEX_Alloc(8 * sizeof(IRType)); @@ -590,6 +606,22 @@ IRTypeEnv* newIRTypeEnv ( void ) return env; } +/* Make an exact copy of the given IRTypeEnv, usually so we can + add new stuff to the copy without messing up the original. */ + +IRTypeEnv* copyIRTypeEnv ( IRTypeEnv* src ) +{ + Int i; + IRTypeEnv* dst = LibVEX_Alloc(sizeof(IRTypeEnv)); + dst->types_size = src->types_size; + dst->types_used = src->types_used; + dst->types = LibVEX_Alloc(dst->types_size * sizeof(IRType)); + for (i = 0; i < src->types_used; i++) + dst->types[i] = src->types[i]; + return dst; +} + +/* Allocate a new IRTemp, given its type. */ IRTemp newIRTemp ( IRTypeEnv* env, IRType ty ) { @@ -613,6 +645,8 @@ IRTemp newIRTemp ( IRTypeEnv* env, IRType ty ) } } +/* Find the type of a temporary previously allocated in an + environment. */ IRType lookupIRTypeEnv ( IRTypeEnv* env, IRTemp tmp ) { @@ -622,6 +656,10 @@ IRType lookupIRTypeEnv ( IRTypeEnv* env, IRTemp tmp ) } +/*---------------------------------------------------------------*/ +/*--- Helper functions for the IR -- finding types of exprs ---*/ +/*---------------------------------------------------------------*/ + IRType typeOfIRConst ( IRConst* con ) { switch (con->tag) { @@ -919,6 +957,11 @@ void sanityCheckIRBB ( IRBB* bb, IRType guest_word_size ) vassert(guest_word_size == Ity_I32 || guest_word_size == Ity_I64); + if (bb->stmts_used < 0 || bb->stmts_size < 8 + || bb->stmts_used > bb->stmts_size) + /* this BB is so strange we can't even print it */ + vpanic("sanityCheckIRBB: stmts array limits wierd"); + /* Ensure each temp has a plausible type. */ for (i = 0; i < n_temps; i++) { IRType ty = lookupIRTypeEnv(bb->tyenv,(IRTemp)i); @@ -935,7 +978,8 @@ void sanityCheckIRBB ( IRBB* bb, IRType guest_word_size ) for (i = 0; i < n_temps; i++) def_counts[i] = 0; - for (stmt = bb->stmts; stmt; stmt=stmt->link) { + for (i = 0; i < bb->stmts_used; i++) { + stmt = bb->stmts[i]; useBeforeDef_Stmt(bb,stmt,def_counts); if (stmt->tag == Ist_Tmp) { if (stmt->Ist.Tmp.tmp < 0 || stmt->Ist.Tmp.tmp >= n_temps) @@ -947,8 +991,8 @@ void sanityCheckIRBB ( IRBB* bb, IRType guest_word_size ) } /* Typecheck everything. */ - for (stmt = bb->stmts; stmt; stmt=stmt->link) - tcStmt( bb, stmt, guest_word_size ); + for (i = 0; i < bb->stmts_used; i++) + tcStmt( bb, bb->stmts[i], guest_word_size ); if (typeOfIRExpr(bb->tyenv,bb->next) != guest_word_size) sanityCheckFail(bb, NULL, "bb->next field has wrong type"); } diff --git a/VEX/priv/ir/iropt.c b/VEX/priv/ir/iropt.c index 9cfcf1e732..240f25bad3 100644 --- a/VEX/priv/ir/iropt.c +++ b/VEX/priv/ir/iropt.c @@ -115,6 +115,152 @@ static void addToH64 ( Hash64* h, ULong key, ULong val ) h->used++; } +/*---------------------------------------------------------------*/ +/*--- Flattening out a BB into pure SSA form ---*/ +/*---------------------------------------------------------------*/ + +/* Clone the NULL-terminated vector of IRExpr*s attached to a + CCall. */ + +static IRExpr** copyIexCCallArgs ( IRExpr** vec ) +{ + Int i; + IRExpr** newvec; + for (i = 0; vec[i]; i++) + ; + newvec = LibVEX_Alloc((i+1)*sizeof(IRExpr*)); + for (i = 0; vec[i]; i++) + newvec[i] = vec[i]; + newvec[i] = NULL; + return newvec; +} + + +/* Flatten out 'ex' so it is atomic, returning a new expression with + the same value, after having appended extra IRTemp assignments to + the end of 'bb'. */ + +static IRExpr* flatten_Expr ( IRBB* bb, IRExpr* ex ) +{ + Int i; + IRExpr** newargs; + IRType ty = typeOfIRExpr(bb->tyenv, ex); + IRTemp t1; + + switch (ex->tag) { + + case Iex_Get: + t1 = newIRTemp(bb->tyenv, ty); + addStmtToIRBB(bb, + IRStmt_Tmp(t1, ex)); + return IRExpr_Tmp(t1); + + case Iex_Binop: + t1 = newIRTemp(bb->tyenv, ty); + addStmtToIRBB(bb, IRStmt_Tmp(t1, + IRExpr_Binop(ex->Iex.Binop.op, + flatten_Expr(bb, ex->Iex.Binop.arg1), + flatten_Expr(bb, ex->Iex.Binop.arg2)))); + return IRExpr_Tmp(t1); + + case Iex_Unop: + t1 = newIRTemp(bb->tyenv, ty); + addStmtToIRBB(bb, IRStmt_Tmp(t1, + IRExpr_Unop(ex->Iex.Unop.op, + flatten_Expr(bb, ex->Iex.Unop.arg)))); + return IRExpr_Tmp(t1); + + case Iex_LDle: + t1 = newIRTemp(bb->tyenv, ty); + addStmtToIRBB(bb, IRStmt_Tmp(t1, + IRExpr_LDle(ex->Iex.LDle.ty, + flatten_Expr(bb, ex->Iex.LDle.addr)))); + return IRExpr_Tmp(t1); + + case Iex_CCall: + newargs = copyIexCCallArgs(ex->Iex.CCall.args); + for (i = 0; newargs[i]; i++) + newargs[i] = flatten_Expr(bb, newargs[i]); + t1 = newIRTemp(bb->tyenv, ty); + addStmtToIRBB(bb, IRStmt_Tmp(t1, + IRExpr_CCall(ex->Iex.CCall.name, + ex->Iex.CCall.retty, + newargs))); + return IRExpr_Tmp(t1); + + case Iex_Mux0X: + t1 = newIRTemp(bb->tyenv, ty); + addStmtToIRBB(bb, IRStmt_Tmp(t1, + IRExpr_Mux0X(flatten_Expr(bb, ex->Iex.Mux0X.cond), + flatten_Expr(bb, ex->Iex.Mux0X.expr0), + flatten_Expr(bb, ex->Iex.Mux0X.exprX)))); + return IRExpr_Tmp(t1); + + case Iex_Const: + case Iex_Tmp: + return ex; + + default: + vex_printf("\n"); + ppIRExpr(ex); + vex_printf("\n"); + vpanic("flatten_Expr"); + } +} + + +/* Append a completely flattened form of 'st' to the end of 'bb'. */ + +static void flatten_Stmt ( IRBB* bb, IRStmt* st ) +{ + IRExpr *e1, *e2; + switch (st->tag) { + case Ist_Put: + e1 = flatten_Expr(bb, st->Ist.Put.expr); + addStmtToIRBB(bb, IRStmt_Put(st->Ist.Put.offset, e1)); + break; +#if 0 + case Ist_PutI: + e1 = flatten_Expr(bb, st->Ist.PutI.offset); + e2 = flatten_Expr(bb, st->Ist.PutI.expr); + addStmtToIRBB(bb, IRStmt_PutI(e1, e2, st->Ist.PutI.minoff, + st->Ist.PutI.maxoff)); + break; +#endif + case Ist_Tmp: + e1 = flatten_Expr(bb, st->Ist.Tmp.expr); + addStmtToIRBB(bb, IRStmt_Tmp(st->Ist.Tmp.tmp, e1)); + break; + case Ist_STle: + e1 = flatten_Expr(bb, st->Ist.STle.addr); + e2 = flatten_Expr(bb, st->Ist.STle.data); + addStmtToIRBB(bb, IRStmt_STle(e1,e2)); + break; + case Ist_Exit: + e1 = flatten_Expr(bb, st->Ist.Exit.cond); + addStmtToIRBB(bb, IRStmt_Exit(e1, st->Ist.Exit.dst)); + break; + default: + vex_printf("\n"); + ppIRStmt(st); + vex_printf("\n"); + vpanic("flatten_Stmt"); + } +} + +static IRBB* flatten_BB ( IRBB* in ) +{ + Int i; + IRBB* out; + out = emptyIRBB(); + out->tyenv = copyIRTypeEnv( in->tyenv ); + for (i = 0; i < in->stmts_used; i++) + flatten_Stmt( out, in->stmts[i] ); + out->next = flatten_Expr( out, in->next ); + out->jumpkind = in->jumpkind; + return out; +} + /*---------------------------------------------------------------*/ /*--- iropt main ---*/ @@ -130,7 +276,8 @@ static void addToH64 ( Hash64* h, ULong key, ULong val ) /* exported from this file */ IRBB* do_iropt_BB ( IRBB* bb0 ) { - return bb0; + IRBB* flat = flatten_BB ( bb0 ); + return flat; } diff --git a/VEX/priv/main/vex_main.c b/VEX/priv/main/vex_main.c index 096d2e8ad0..fb88ae4cc0 100644 --- a/VEX/priv/main/vex_main.c +++ b/VEX/priv/main/vex_main.c @@ -174,6 +174,7 @@ TranslateResult LibVEX_Translate ( /* Clean it up, hopefully a lot. */ irbb = do_iropt_BB ( irbb ); + sanityCheckIRBB(irbb, Ity_I32); if (vex_verbosity > 0) { vex_printf("\n-------- After IR optimisation --------\n"); diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index cdcb9fc01d..b97e10ec29 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -285,7 +285,6 @@ typedef IRConst* dst; } Exit; } Ist; - struct _IRStmt* link; } IRStmt; @@ -342,22 +341,27 @@ typedef extern void ppIRTypeEnv ( IRTypeEnv* ); -/* Basic blocks contain 4 fields: +/* Basic blocks contain: - A table giving a type for each temp - - A list of statements + - An expandable array of statements - An expression of type 32 or 64 bits, depending on the guest's word size, indicating the next destination. + - An indication of any special actions (JumpKind) needed + for this final jump. */ typedef struct _IRBB { IRTypeEnv* tyenv; - IRStmt* stmts; + IRStmt** stmts; + Int stmts_size; + Int stmts_used; IRExpr* next; IRJumpKind jumpkind; } IRBB; -extern IRBB* mkIRBB ( IRTypeEnv*, IRStmt*, IRExpr*, IRJumpKind ); +extern IRBB* emptyIRBB ( void ); +extern void addStmtToIRBB ( IRBB*, IRStmt* ); extern void ppIRBB ( IRBB* ); @@ -367,9 +371,10 @@ extern void ppIRBB ( IRBB* ); /*---------------------------------------------------------------*/ /* For messing with IR type environments */ -extern IRTypeEnv* newIRTypeEnv ( void ); +extern IRTypeEnv* emptyIRTypeEnv ( void ); extern IRTemp newIRTemp ( IRTypeEnv*, IRType ); extern IRType lookupIRTypeEnv ( IRTypeEnv*, IRTemp ); +extern IRTypeEnv* copyIRTypeEnv ( IRTypeEnv* ); /* What is the type of this expression? */ extern IRType typeOfIRConst ( IRConst* );