From: Julian Seward Date: Sun, 29 Apr 2007 09:57:48 +0000 (+0000) Subject: Merge r1738 (comment only changes for the ppc front end) X-Git-Tag: svn/VALGRIND_3_2_3^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3f97a1ec0afbd818384dbd080a5e9d7d01501ad0;p=thirdparty%2Fvalgrind.git Merge r1738 (comment only changes for the ppc front end) Merge r1739 (ppc64 code generation bug fix: When generating 64-bit code, ensure that any addresses used in 4 or 8 byte loads or stores of the form reg+imm have the lowest 2 bits of imm set to zero, so that they can safely be used in ld/ldu/lda/std/stdu instructions.) git-svn-id: svn://svn.valgrind.org/vex/branches/VEX_3_2_BRANCH@1753 --- diff --git a/VEX/priv/guest-ppc/toIR.c b/VEX/priv/guest-ppc/toIR.c index 64b8c00da5..76913924d9 100644 --- a/VEX/priv/guest-ppc/toIR.c +++ b/VEX/priv/guest-ppc/toIR.c @@ -3495,7 +3495,8 @@ static Bool dis_int_load ( UInt theInstr ) 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 ) ); @@ -3687,9 +3688,10 @@ static Bool dis_int_load ( UInt theInstr ) } 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)) ); @@ -3701,7 +3703,6 @@ static Bool dis_int_load ( UInt theInstr ) 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; @@ -3755,7 +3756,8 @@ static Bool dis_int_store ( UInt theInstr ) 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 ) ); @@ -3884,9 +3886,10 @@ static Bool dis_int_store ( UInt theInstr ) } 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) ); diff --git a/VEX/priv/host-ppc/hdefs.c b/VEX/priv/host-ppc/hdefs.c index e9712b2cfd..cc21c1b484 100644 --- a/VEX/priv/host-ppc/hdefs.c +++ b/VEX/priv/host-ppc/hdefs.c @@ -1301,7 +1301,7 @@ void ppPPCInstr ( PPCInstr* i, Bool mode64 ) 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); @@ -2388,8 +2388,9 @@ static UChar* doAMode_IR ( UChar* p, UInt opc1, UInt rSD, 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; @@ -3028,6 +3029,10 @@ Int emit_PPCInstr ( UChar* buf, Int nbuf, PPCInstr* i, 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; @@ -3099,6 +3104,10 @@ Int emit_PPCInstr ( UChar* buf, Int nbuf, PPCInstr* i, 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; diff --git a/VEX/priv/host-ppc/isel.c b/VEX/priv/host-ppc/isel.c index 082d38d3c9..a7cd103c7e 100644 --- a/VEX/priv/host-ppc/isel.c +++ b/VEX/priv/host-ppc/isel.c @@ -374,16 +374,25 @@ static PPCRI* iselWordExpr_RI ( ISelEnv* env, IRExpr* e ); 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, @@ -1150,7 +1159,7 @@ static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e ) /* --------- 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)), @@ -1502,7 +1511,7 @@ static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e ) 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; } @@ -1900,6 +1909,11 @@ static Bool uLong_fits_in_16_bits ( ULong u ) 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; @@ -1920,20 +1934,30 @@ static Bool sane_AMode ( ISelEnv* env, PPCAMode* am ) } } -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) */ @@ -1941,6 +1965,9 @@ static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e ) && 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, @@ -2799,7 +2826,7 @@ static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e ) 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; } @@ -2947,7 +2974,7 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) 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; } @@ -3194,7 +3221,7 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) 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; } @@ -3601,7 +3628,7 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) ( 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);