case 0x1F: // register offset
assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
break;
- case 0x3A: // immediate offset: 64bit
+ case 0x3A: // immediate offset: 64bit: ld/ldu/lwa: mask off
+ // lowest 2 bits of immediate before forming EA
simm16 = simm16 & 0xFFFFFFFC;
default: // immediate offset
assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
}
break;
- /* DS Form - 64bit Loads */
+ /* DS Form - 64bit Loads. In each case EA will have been formed
+ with the lowest 2 bits masked off the immediate offset. */
case 0x3A:
- switch (b1<<1 | b0) {
+ switch ((b1<<1) | b0) {
case 0x0: // ld (Load DWord, PPC64 p472)
DIP("ld r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
putIReg( rD_addr, loadBE(Ity_I64, mkexpr(EA)) );
return False;
}
DIP("ldu r%u,%d(r%u)\n", rD_addr, simm16, rA_addr);
- simm16 = simm16 & ~0x3;
putIReg( rD_addr, loadBE(Ity_I64, mkexpr(EA)) );
putIReg( rA_addr, mkexpr(EA) );
break;
case 0x1F: // register offset
assign( EA, ea_rAor0_idxd( rA_addr, rB_addr ) );
break;
- case 0x3E: // immediate offset: 64bit
+ case 0x3E: // immediate offset: 64bit: std/stdu: mask off
+ // lowest 2 bits of immediate before forming EA
simm16 = simm16 & 0xFFFFFFFC;
default: // immediate offset
assign( EA, ea_rAor0_simm( rA_addr, simm16 ) );
}
break;
- /* DS Form - 64bit Stores */
+ /* DS Form - 64bit Stores. In each case EA will have been formed
+ with the lowest 2 bits masked off the immediate offset. */
case 0x3E:
- switch (b1<<1 | b0) {
+ switch ((b1<<1) | b0) {
case 0x0: // std (Store DWord, PPC64 p580)
DIP("std r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
storeBE( mkexpr(EA), mkexpr(rS) );
Bool idxd = toBool(i->Pin.Load.src->tag == Pam_RR);
UChar sz = i->Pin.Load.sz;
UChar c_sz = sz==1 ? 'b' : sz==2 ? 'h' : sz==4 ? 'w' : 'd';
- vex_printf("l%cz%s ", c_sz, idxd ? "x" : "" );
+ vex_printf("l%c%s%s ", c_sz, sz==8 ? "" : "z", idxd ? "x" : "" );
ppHRegPPC(i->Pin.Load.dst);
vex_printf(",");
ppPPCAMode(i->Pin.Load.src);
if (opc1 == 58 || opc1 == 62) { // ld/std: mode64 only
vassert(mode64);
- // kludge DS form: lowest 2 bits = 00
- idx &= 0xFFFC;
+ /* stay sane with DS form: lowest 2 bits must be 00. This
+ should be guaranteed to us by iselWordExpr_AMode. */
+ vassert(0 == (idx & 3));
}
p = mkFormD(p, opc1, rSD, rA, idx);
return p;
UInt opc1, opc2, sz = i->Pin.Load.sz;
switch (am_addr->tag) {
case Pam_IR:
+ if (mode64 && (sz == 4 || sz == 8)) {
+ /* should be guaranteed to us by iselWordExpr_AMode */
+ vassert(0 == (am_addr->Pam.IR.index & 3));
+ }
switch(sz) {
case 1: opc1 = 34; break;
case 2: opc1 = 40; break;
UInt opc1, opc2, sz = i->Pin.Store.sz;
switch (i->Pin.Store.dst->tag) {
case Pam_IR:
+ if (mode64 && (sz == 4 || sz == 8)) {
+ /* should be guaranteed to us by iselWordExpr_AMode */
+ vassert(0 == (am_addr->Pam.IR.index & 3));
+ }
switch(sz) {
case 1: opc1 = 38; break;
case 2: opc1 = 44; break;
static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e );
static PPCRH* iselWordExpr_RH5u ( ISelEnv* env, IRExpr* e );
-/* In 64-bit mode ONLY, compute an I8 into a Compute an I8 into a
+/* In 64-bit mode ONLY, compute an I8 into a
reg-or-6-bit-unsigned-immediate, the latter being an immediate in
the range 1 .. 63 inclusive. Used for doing shift amounts. */
static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e );
static PPCRH* iselWordExpr_RH6u ( ISelEnv* env, IRExpr* e );
/* 32-bit mode: compute an I32 into an AMode.
- 64-bit mode: compute an I64 into an AMode. */
-static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e );
-static PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e );
+ 64-bit mode: compute an I64 into an AMode.
+
+ Requires to know (xferTy) the type of data to be loaded/stored
+ using this amode. That is so that, for 64-bit code generation, any
+ PPCAMode_IR returned will have an index (immediate offset) field
+ that is guaranteed to be 4-aligned, if there is any chance that the
+ amode is to be used in ld/ldu/lda/std/stdu.
+
+ Since there are no such restrictions on 32-bit insns, xferTy is
+ ignored for 32-bit code generation. */
+static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e, IRType xferTy );
+static PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e, IRType xferTy );
/* 32-bit mode ONLY: compute an I64 into a GPR pair. */
static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
/* --------- LOAD --------- */
case Iex_Load: {
HReg r_dst = newVRegI(env);
- PPCAMode* am_addr = iselWordExpr_AMode( env, e->Iex.Load.addr );
+ PPCAMode* am_addr = iselWordExpr_AMode( env, e->Iex.Load.addr, ty/*of xfer*/ );
if (e->Iex.Load.end != Iend_BE)
goto irreducible;
addInstr(env, PPCInstr_Load( toUChar(sizeofIRType(ty)),
IRExpr_Load(Iend_BE,Ity_I16,bind(0))) );
if (matchIRExpr(&mi,p_LDbe16_then_16Uto32,e)) {
HReg r_dst = newVRegI(env);
- PPCAMode* amode = iselWordExpr_AMode( env, mi.bindee[0] );
+ PPCAMode* amode = iselWordExpr_AMode( env, mi.bindee[0], Ity_I16/*xfer*/ );
addInstr(env, PPCInstr_Load(2,r_dst,amode, mode64));
return r_dst;
}
return toBool(u == (ULong)i);
}
+static Bool uLong_is_4_aligned ( ULong u )
+{
+ return toBool((u & 3ULL) == 0);
+}
+
static Bool sane_AMode ( ISelEnv* env, PPCAMode* am )
{
Bool mode64 = env->mode64;
}
}
-static PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e )
+static
+PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e, IRType xferTy )
{
- PPCAMode* am = iselWordExpr_AMode_wrk(env, e);
+ PPCAMode* am = iselWordExpr_AMode_wrk(env, e, xferTy);
vassert(sane_AMode(env, am));
return am;
}
/* DO NOT CALL THIS DIRECTLY ! */
-static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e )
+static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e, IRType xferTy )
{
IRType ty = typeOfIRExpr(env->type_env,e);
if (env->mode64) {
+ /* If the data load/store type is I32 or I64, this amode might
+ be destined for use in ld/ldu/lwa/st/stu. In which case
+ insist that if it comes out as an _IR, the immediate must
+ have its bottom two bits be zero. This does assume that for
+ any other type (I8/I16/I128/F32/F64/V128) the amode will not
+ be parked in any such instruction. But that seems a
+ reasonable assumption. */
+ Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64);
+
vassert(ty == Ity_I64);
/* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
&& e->Iex.Binop.op == Iop_Add64
&& e->Iex.Binop.arg2->tag == Iex_Const
&& e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64
+ && (aligned4imm ? uLong_is_4_aligned(e->Iex.Binop.arg2
+ ->Iex.Const.con->Ico.U64)
+ : True)
&& uLong_fits_in_16_bits(e->Iex.Binop.arg2
->Iex.Const.con->Ico.U64)) {
return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U64,
PPCAMode* am_addr;
HReg r_dst = newVRegF(env);
vassert(e->Iex.Load.ty == Ity_F32);
- am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr);
+ am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F32/*xfer*/);
addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
return r_dst;
}
HReg r_dst = newVRegF(env);
PPCAMode* am_addr;
vassert(e->Iex.Load.ty == Ity_F64);
- am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr);
+ am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F64/*xfer*/);
addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
return r_dst;
}
PPCAMode* am_addr;
HReg v_dst = newVRegV(env);
vassert(e->Iex.Load.ty == Ity_V128);
- am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr);
+ am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_V128/*xfer*/);
addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, v_dst, am_addr));
return v_dst;
}
( mode64 && (tya != Ity_I64)) )
goto stmt_fail;
- am_addr = iselWordExpr_AMode(env, stmt->Ist.Store.addr);
+ am_addr = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/);
if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
(mode64 && (tyd == Ity_I64))) {
HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data);