From: Florian Krohm Date: Sat, 22 Nov 2014 20:10:21 +0000 (+0000) Subject: Add function s390_isel_amode_b12_b20 to compile an expression into an X-Git-Tag: svn/VALGRIND_3_11_0^2~151 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=05126537376db65414bb153ba59ca33bad2aa8b2;p=thirdparty%2Fvalgrind.git Add function s390_isel_amode_b12_b20 to compile an expression into an amode that is either S390_AMODE_B12 or S390_AMODE_B20. This is needed for compare-and-swap insns. As we're currently not generating amodes using an index register, there was never a problem. This change future-proofs the code. Also add a few more asserts for amodes in the s390_insns supporting translation chaining. Fixes BZ #269360. git-svn-id: svn://svn.valgrind.org/vex/trunk@3000 --- diff --git a/VEX/priv/host_s390_defs.c b/VEX/priv/host_s390_defs.c index e5f0076557..cce67acacf 100644 --- a/VEX/priv/host_s390_defs.c +++ b/VEX/priv/host_s390_defs.c @@ -5592,6 +5592,7 @@ s390_insn_cas(UChar size, HReg op1, s390_amode *op2, HReg op3, HReg old_mem) vassert(size == 4 || size == 8); vassert(hregNumber(op2->x) == 0); + vassert(op2->tag == S390_AMODE_B12 || op2->tag == S390_AMODE_B20); insn->tag = S390_INSN_CAS; insn->size = size; @@ -5615,6 +5616,7 @@ s390_insn_cdas(UChar size, HReg op1_high, HReg op1_low, s390_amode *op2, vassert(size == 4 || size == 8); vassert(hregNumber(op2->x) == 0); vassert(hregNumber(scratch) == 1); /* r0,r1 used as scratch reg pair */ + vassert(op2->tag == S390_AMODE_B12 || op2->tag == S390_AMODE_B20); insn->tag = S390_INSN_CDAS; insn->size = size; @@ -6345,6 +6347,8 @@ s390_insn_xdirect(s390_cc_t cond, Addr64 dst, s390_amode *guest_IA, { s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn)); + vassert(guest_IA->tag == S390_AMODE_B12); + insn->tag = S390_INSN_XDIRECT; insn->size = 0; /* does not matter */ @@ -6362,6 +6366,8 @@ s390_insn_xindir(s390_cc_t cond, HReg dst, s390_amode *guest_IA) { s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn)); + vassert(guest_IA->tag == S390_AMODE_B12); + insn->tag = S390_INSN_XINDIR; insn->size = 0; /* does not matter */ @@ -6379,6 +6385,8 @@ s390_insn_xassisted(s390_cc_t cond, HReg dst, s390_amode *guest_IA, { s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn)); + vassert(guest_IA->tag == S390_AMODE_B12); + insn->tag = S390_INSN_XASSISTED; insn->size = 0; /* does not matter */ @@ -8185,9 +8193,11 @@ s390_insn_cas_emit(UChar *buf, const s390_insn *insn) b = hregNumber(am->b); d = am->d; + vassert(am->tag == S390_AMODE_B12 || am->tag == S390_AMODE_B20); + switch (insn->size) { case 4: - /* r1 must no be overwritten. So copy it to R0 and let CS clobber it */ + /* r1 must not be overwritten. So copy it to R0 and let CS clobber it */ buf = s390_emit_LR(buf, R0, r1); if (am->tag == S390_AMODE_B12) buf = s390_emit_CS(buf, R0, r3, b, d); @@ -8197,7 +8207,7 @@ s390_insn_cas_emit(UChar *buf, const s390_insn *insn) return s390_emit_LR(buf, old, R0); case 8: - /* r1 must no be overwritten. So copy it to R0 and let CS clobber it */ + /* r1 must not be overwritten. So copy it to R0 and let CS clobber it */ buf = s390_emit_LGR(buf, R0, r1); buf = s390_emit_CSG(buf, R0, r3, b, DISP20(d)); /* Now copy R0 which has the old memory value to OLD */ @@ -8233,6 +8243,7 @@ s390_insn_cdas_emit(UChar *buf, const s390_insn *insn) d = am->d; vassert(scratch == 1); + vassert(am->tag == S390_AMODE_B12 || am->tag == S390_AMODE_B20); switch (insn->size) { case 4: diff --git a/VEX/priv/host_s390_isel.c b/VEX/priv/host_s390_isel.c index 6affc04957..fc320144e1 100644 --- a/VEX/priv/host_s390_isel.c +++ b/VEX/priv/host_s390_isel.c @@ -127,6 +127,7 @@ typedef struct { /* Forward declarations */ static HReg s390_isel_int_expr(ISelEnv *, IRExpr *); static s390_amode *s390_isel_amode(ISelEnv *, IRExpr *); +static s390_amode *s390_isel_amode_b12_b20(ISelEnv *, IRExpr *); static s390_cc_t s390_isel_cc(ISelEnv *, IRExpr *); static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *); static void s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *); @@ -286,9 +287,11 @@ ulong_fits_signed_8bit(ULong val) } /* EXPR is an expression that is used as an address. Return an s390_amode - for it. */ + for it. If select_b12_b20_only is true the returned amode must be either + S390_AMODE_B12 or S390_AMODE_B20. */ static s390_amode * -s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr) +s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr, + Bool select_b12_b20_only __attribute__((unused))) { if (expr->tag == Iex_Binop && expr->Iex.Binop.op == Iop_Add64) { IRExpr *arg1 = expr->Iex.Binop.arg1; @@ -331,7 +334,7 @@ s390_isel_amode(ISelEnv *env, IRExpr *expr) /* Address computation should yield a 64-bit value */ vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64); - am = s390_isel_amode_wrk(env, expr); + am = s390_isel_amode_wrk(env, expr, /* B12, B20 only */ False); /* Check post-condition */ vassert(s390_amode_is_sane(am)); @@ -340,6 +343,38 @@ s390_isel_amode(ISelEnv *env, IRExpr *expr) } +/* Sometimes we must compile an expression into an amode that is either + S390_AMODE_B12 or S390_AMODE_B20. An example is the compare-and-swap + opcode. These opcodes do not have a variant hat accepts an addressing + mode with an index register. + Now, in theory we could, when emitting the compare-and-swap insn, + hack a, say, BX12 amode into a B12 amode like so: + + r0 = b # save away base register + b = b + x # add index register to base register + cas(b,d,...) # emit compare-and-swap using b12 amode + b = r0 # restore base register + + Unfortunately, emitting the compare-and-swap insn already utilises r0 + under the covers, so the trick above is off limits, sadly. */ +static s390_amode * +s390_isel_amode_b12_b20(ISelEnv *env, IRExpr *expr) +{ + s390_amode *am; + + /* Address computation should yield a 64-bit value */ + vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64); + + am = s390_isel_amode_wrk(env, expr, /* B12, B20 only */ True); + + /* Check post-condition */ + vassert(s390_amode_is_sane(am) && + (am->tag == S390_AMODE_B12 || am->tag == S390_AMODE_B20)); + + return am; +} + + /*---------------------------------------------------------*/ /*--- Helper functions ---*/ /*---------------------------------------------------------*/ @@ -3781,7 +3816,7 @@ no_memcpy_put: case Ist_CAS: if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) { IRCAS *cas = stmt->Ist.CAS.details; - s390_amode *op2 = s390_isel_amode(env, cas->addr); + s390_amode *op2 = s390_isel_amode_b12_b20(env, cas->addr); HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */ HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */ HReg old = lookupIRTemp(env, cas->oldLo); @@ -3794,7 +3829,7 @@ no_memcpy_put: return; } else { IRCAS *cas = stmt->Ist.CAS.details; - s390_amode *op2 = s390_isel_amode(env, cas->addr); + s390_amode *op2 = s390_isel_amode_b12_b20(env, cas->addr); HReg r8, r9, r10, r11, r1; HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */ HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */