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;
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;
{
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 */
{
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 */
{
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 */
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);
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 */
d = am->d;
vassert(scratch == 1);
+ vassert(am->tag == S390_AMODE_B12 || am->tag == S390_AMODE_B20);
switch (insn->size) {
case 4:
/* 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 *);
}
/* 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;
/* 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));
}
+/* 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 ---*/
/*---------------------------------------------------------*/
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);
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 */