]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Merge r1738 (comment only changes for the ppc front end)
authorJulian Seward <jseward@acm.org>
Sun, 29 Apr 2007 09:57:48 +0000 (09:57 +0000)
committerJulian Seward <jseward@acm.org>
Sun, 29 Apr 2007 09:57:48 +0000 (09:57 +0000)
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

VEX/priv/guest-ppc/toIR.c
VEX/priv/host-ppc/hdefs.c
VEX/priv/host-ppc/isel.c

index 64b8c00da597ed0b971db00ab55cea968f3b37d8..76913924d9fe6bb1bc16a6b409f320fb5de6c044 100644 (file)
@@ -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) );
index e9712b2cfd2ec5651c94bb13ff10119094182a04..cc21c1b4843aea019ebe6704c85f5c86627e3189 100644 (file)
@@ -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;
index 082d38d3c96be4b956af5eb0c4ee544f07400cb4..a7cd103c7e0808cb7aba997cb928e540b35ba9ba 100644 (file)
@@ -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);