From f8afeb76e76700dcf7fc2716d97eba9cd5abb6af Mon Sep 17 00:00:00 2001 From: Ivo Raisr Date: Tue, 8 Aug 2017 09:47:24 +0200 Subject: [PATCH] Support If-Then-Else in x86 isel backend. --- VEX/priv/host_x86_isel.c | 165 +++++++++++++++++++++++++++++++++------ 1 file changed, 142 insertions(+), 23 deletions(-) diff --git a/VEX/priv/host_x86_isel.c b/VEX/priv/host_x86_isel.c index 45aafeb5f7..721c159c23 100644 --- a/VEX/priv/host_x86_isel.c +++ b/VEX/priv/host_x86_isel.c @@ -124,6 +124,19 @@ static Bool isZeroU32 ( IRExpr* e ) // && e->Iex.Const.con->Ico.U64 == 0ULL; //} +static void print_depth(UInt depth) +{ + for (UInt i = 0; i < depth; i++) { + vex_printf(" "); + } +} + +static void print_IRStmt_prefix(UInt depth) +{ + vex_printf("\n"); + print_depth(depth); + vex_printf("-- "); +} /*---------------------------------------------------------*/ /*--- ISelEnv ---*/ @@ -147,7 +160,8 @@ static Bool isZeroU32 ( IRExpr* e ) 32-bit virtual HReg, which holds the high half of the value. - - The code array, that is, the insns selected so far. + - The code vector, that is, the insns selected so far. HInstrVec 'code' + changes according to the current IRStmtVec being processed. - A counter, for generating new virtual registers. @@ -172,11 +186,12 @@ static Bool isZeroU32 ( IRExpr* e ) typedef struct { /* Constant -- are set at the start and do not change. */ - IRTypeEnv* type_env; + HInstrSB* code_sb; + const IRTypeEnv* type_env; HReg* vregmap; HReg* vregmapHI; - Int n_vregmap; + UInt n_vregmap; UInt hwcaps; @@ -184,8 +199,9 @@ typedef Addr32 max_ga; /* These are modified as we go along. */ - HInstrArray* code; - Int vreg_ctr; + HInstrVec* code; + UInt vreg_ctr; + UInt depth; } ISelEnv; @@ -210,6 +226,7 @@ static void addInstr ( ISelEnv* env, X86Instr* instr ) { addHInstr(env->code, instr); if (vex_traceflags & VEX_TRACE_VCODE) { + print_depth(env->depth); ppX86Instr(instr, False); vex_printf("\n"); } @@ -3859,11 +3876,114 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, const IRExpr* e ) /*--- ISEL: Statements ---*/ /*---------------------------------------------------------*/ +static void iselStmt(ISelEnv* env, IRStmt* stmt); + +static HPhiNode* convertPhiNodes(ISelEnv* env, const IRPhiVec* phi_nodes, + IRIfThenElse_Hint hint, UInt *n_phis) +{ + *n_phis = phi_nodes->phis_used; + HPhiNode* hphis = LibVEX_Alloc_inline(*n_phis * sizeof(HPhiNode)); + + for (UInt i = 0; i < *n_phis; i++) { + const IRPhi* phi = phi_nodes->phis[i]; + hphis[i].dst = lookupIRTemp(env, phi->dst); + + switch (hint) { + case IfThenElse_ThenLikely: + hphis[i].srcFallThrough = lookupIRTemp(env, phi->srcThen); + hphis[i].srcOutOfLine = lookupIRTemp(env, phi->srcElse); + break; + case IfThenElse_ElseLikely: + hphis[i].srcFallThrough = lookupIRTemp(env, phi->srcElse); + hphis[i].srcOutOfLine = lookupIRTemp(env, phi->srcThen); + break; + default: + vassert(0); + } + } + return hphis; +} + +static void iselStmtVec(ISelEnv* env, IRStmtVec* stmts) +{ + for (UInt i = 0; i < stmts->stmts_used; i++) { + IRStmt* st = stmts->stmts[i]; + if (st->tag != Ist_IfThenElse) { + iselStmt(env, stmts->stmts[i]); + continue; + } + + /* Deal with IfThenElse. */ + HInstrVec* current_code = env->code; + IRIfThenElse* ite = st->Ist.IfThenElse.details; + if (vex_traceflags & VEX_TRACE_VCODE) { + print_IRStmt_prefix(env->depth); + ppIRIfThenElseCondHint(ite); + vex_printf(" then {\n"); + } + + UInt n_phis; + HPhiNode* phi_nodes = convertPhiNodes(env, ite->phi_nodes, + ite->hint, &n_phis); + + X86CondCode cc = iselCondCode(env, ite->cond); + /* Note: do not insert any instructions which alter |cc| before it + is consumed by the corresponding branch. */ + HInstrIfThenElse* hite = newHInstrIfThenElse(cc, phi_nodes, n_phis); + X86Instr* instr = X86Instr_IfThenElse(hite); + addInstr(env, instr); + + env->depth += 1; + + IRStmtVec* likely_leg; + IRStmtVec* unlikely_leg; + switch (ite->hint) { + case IfThenElse_ThenLikely: + likely_leg = ite->then_leg; + unlikely_leg = ite->else_leg; + break; + case IfThenElse_ElseLikely: + likely_leg = ite->else_leg; + unlikely_leg = ite->then_leg; + break; + default: + vassert(0); + } + + env->code = hite->fallThrough; + iselStmtVec(env, likely_leg); + if (vex_traceflags & VEX_TRACE_VCODE) { + print_IRStmt_prefix(env->depth - 1); + vex_printf("} else {\n"); + } + env->code = hite->outOfLine; + iselStmtVec(env, unlikely_leg); + + env->depth -= 1; + env->code = current_code; + + if (vex_traceflags & VEX_TRACE_VCODE) { + print_IRStmt_prefix(env->depth); + vex_printf("}\n"); + + for (UInt j = 0; j < hite->n_phis; j++) { + print_IRStmt_prefix(env->depth); + ppIRPhi(ite->phi_nodes->phis[j]); + vex_printf("\n"); + + print_depth(env->depth); + ppHPhiNode(&hite->phi_nodes[j]); + vex_printf("\n"); + } + } + } +} + static void iselStmt ( ISelEnv* env, IRStmt* stmt ) { if (vex_traceflags & VEX_TRACE_VCODE) { - vex_printf("\n-- "); - ppIRStmt(stmt); + print_IRStmt_prefix(env->depth); + ppIRStmt(stmt, env->type_env, 0); vex_printf("\n"); } @@ -4309,7 +4429,7 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) default: break; } stmt_fail: - ppIRStmt(stmt); + ppIRStmt(stmt, env->type_env, 0); vpanic("iselStmt"); } @@ -4419,7 +4539,7 @@ static void iselNext ( ISelEnv* env, /* Translate an entire SB to x86 code. */ -HInstrArray* iselSB_X86 ( const IRSB* bb, +HInstrSB* iselSB_X86 ( const IRSB* bb, VexArch arch_host, const VexArchInfo* archinfo_host, const VexAbiInfo* vbi/*UNUSED*/, @@ -4429,9 +4549,6 @@ HInstrArray* iselSB_X86 ( const IRSB* bb, Bool addProfInc, Addr max_ga ) { - Int i, j; - HReg hreg, hregHI; - ISelEnv* env; UInt hwcaps_host = archinfo_host->hwcaps; X86AMode *amCounter, *amFailAddr; @@ -4448,18 +4565,20 @@ HInstrArray* iselSB_X86 ( const IRSB* bb, vassert(archinfo_host->endness == VexEndnessLE); /* Make up an initial environment to use. */ - env = LibVEX_Alloc_inline(sizeof(ISelEnv)); + ISelEnv* env = LibVEX_Alloc_inline(sizeof(ISelEnv)); env->vreg_ctr = 0; - /* Set up output code array. */ - env->code = newHInstrArray(); + /* Set up output HInstrSB and the first processed HInstrVec. */ + env->code_sb = newHInstrSB(); + env->code = env->code_sb->insns; + env->depth = 0; /* Copy BB's type env. */ env->type_env = bb->tyenv; /* Make up an IRTemp -> virtual HReg mapping. This doesn't change as we go along. */ - env->n_vregmap = bb->tyenv->types_used; + env->n_vregmap = bb->tyenv->used; env->vregmap = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg)); env->vregmapHI = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg)); @@ -4470,9 +4589,10 @@ HInstrArray* iselSB_X86 ( const IRSB* bb, /* For each IR temporary, allocate a suitably-kinded virtual register. */ - j = 0; - for (i = 0; i < env->n_vregmap; i++) { - hregHI = hreg = INVALID_HREG; + UInt j = 0; + for (UInt i = 0; i < env->n_vregmap; i++) { + HReg hreg = INVALID_HREG; + HReg hregHI = INVALID_HREG; switch (bb->tyenv->types[i]) { case Ity_I1: case Ity_I8: @@ -4505,14 +4625,13 @@ HInstrArray* iselSB_X86 ( const IRSB* bb, } /* Ok, finally we can iterate over the statements. */ - for (i = 0; i < bb->stmts_used; i++) - iselStmt(env, bb->stmts[i]); + iselStmtVec(env, bb->stmts); iselNext(env, bb->next, bb->jumpkind, bb->offsIP); /* record the number of vregs we used. */ - env->code->n_vregs = env->vreg_ctr; - return env->code; + env->code_sb->n_vregs = env->vreg_ctr; + return env->code_sb; } -- 2.47.2