Merge, from branches/COMEM, revisions 2568 to 2641.


git-svn-id: svn://svn.valgrind.org/vex/trunk@2642 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/host_arm_isel.c b/priv/host_arm_isel.c
index 8cb985a..b19e6c4 100644
--- a/priv/host_arm_isel.c
+++ b/priv/host_arm_isel.c
@@ -378,7 +378,8 @@
 static
 Bool doHelperCall ( ISelEnv* env,
                     Bool passBBP,
-                    IRExpr* guard, IRCallee* cee, IRExpr** args )
+                    IRExpr* guard, IRCallee* cee, IRExpr** args,
+                    RetLoc rloc )
 {
    ARMCondCode cc;
    HReg        argregs[ARM_N_ARGREGS];
@@ -615,7 +616,7 @@
       values.  But that's too much hassle. */
 
    /* Finally, the call itself. */
-   addInstr(env, ARMInstr_Call( cc, target, nextArgReg ));
+   addInstr(env, ARMInstr_Call( cc, target, nextArgReg, rloc ));
 
    return True; /* success */
 }
@@ -1087,7 +1088,6 @@
 {
    IRType ty = typeOfIRExpr(env->type_env,e);
    vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
-//   vassert(ty == Ity_I64 || ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
 
    switch (e->tag) {
 
@@ -1105,29 +1105,21 @@
 
       if (ty == Ity_I32) {
          ARMAMode1* amode = iselIntExpr_AMode1 ( env, e->Iex.Load.addr );
-         addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, dst, amode));
+         addInstr(env, ARMInstr_LdSt32(ARMcc_AL, True/*isLoad*/, dst, amode));
          return dst;
       }
       if (ty == Ity_I16) {
          ARMAMode2* amode = iselIntExpr_AMode2 ( env, e->Iex.Load.addr );
-         addInstr(env, ARMInstr_LdSt16(True/*isLoad*/, False/*!signedLoad*/,
+         addInstr(env, ARMInstr_LdSt16(ARMcc_AL,
+                                       True/*isLoad*/, False/*!signedLoad*/,
                                        dst, amode));
          return dst;
       }
       if (ty == Ity_I8) {
          ARMAMode1* amode = iselIntExpr_AMode1 ( env, e->Iex.Load.addr );
-         addInstr(env, ARMInstr_LdSt8U(True/*isLoad*/, dst, amode));
+         addInstr(env, ARMInstr_LdSt8U(ARMcc_AL, True/*isLoad*/, dst, amode));
          return dst;
       }
-
-//zz      if (ty == Ity_I16) {
-//zz         addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
-//zz         return dst;
-//zz      }
-//zz      if (ty == Ity_I8) {
-//zz         addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
-//zz         return dst;
-//zz      }
       break;
    }
 
@@ -1378,7 +1370,8 @@
          HReg res  = newVRegI(env);
          addInstr(env, mk_iMOVds_RR(hregARM_R0(), regL));
          addInstr(env, mk_iMOVds_RR(hregARM_R1(), regR));
-         addInstr(env, ARMInstr_Call( ARMcc_AL, (HWord)Ptr_to_ULong(fn), 2 ));
+         addInstr(env, ARMInstr_Call( ARMcc_AL, (HWord)Ptr_to_ULong(fn),
+                                      2, RetLocInt ));
          addInstr(env, mk_iMOVds_RR(res, hregARM_R0()));
          return res;
       }
@@ -1665,7 +1658,8 @@
          HReg arg = iselIntExpr_R(env, e->Iex.Unop.arg);
          HReg res = newVRegI(env);
          addInstr(env, mk_iMOVds_RR(hregARM_R0(), arg));
-         addInstr(env, ARMInstr_Call( ARMcc_AL, (HWord)Ptr_to_ULong(fn), 1 ));
+         addInstr(env, ARMInstr_Call( ARMcc_AL, (HWord)Ptr_to_ULong(fn),
+                                      1, RetLocInt ));
          addInstr(env, mk_iMOVds_RR(res, hregARM_R0()));
          return res;
       }
@@ -1680,7 +1674,7 @@
           && e->Iex.Get.offset < 4096-4) {
          HReg dst = newVRegI(env);
          addInstr(env, ARMInstr_LdSt32(
-                          True/*isLoad*/,
+                          ARMcc_AL, True/*isLoad*/,
                           dst,
                           ARMAMode1_RI(hregARM_R8(), e->Iex.Get.offset)));
          return dst;
@@ -1719,14 +1713,16 @@
       HReg    dst = newVRegI(env);
       vassert(ty == e->Iex.CCall.retty);
 
-      /* be very restrictive for now.  Only 32/64-bit ints allowed
-         for args, and 32 bits for return type. */
+      /* be very restrictive for now.  Only 32/64-bit ints allowed for
+         args, and 32 bits for return type.  Don't forget to change
+         the RetLoc if more types are allowed in future. */
       if (e->Iex.CCall.retty != Ity_I32)
          goto irreducible;
 
       /* Marshal args, do the call, clear stack. */
       Bool ok = doHelperCall( env, False,
-                              NULL, e->Iex.CCall.cee, e->Iex.CCall.args );
+                              NULL, e->Iex.CCall.cee, e->Iex.CCall.args,
+                              RetLocInt );
       if (ok) {
          addInstr(env, mk_iMOVds_RR(dst, hregARM_R0()));
          return dst;
@@ -1858,8 +1854,10 @@
       rA  = iselIntExpr_R(env, e->Iex.Load.addr);
       tHi = newVRegI(env);
       tLo = newVRegI(env);
-      addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tHi, ARMAMode1_RI(rA, 4)));
-      addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tLo, ARMAMode1_RI(rA, 0)));
+      addInstr(env, ARMInstr_LdSt32(ARMcc_AL, True/*isLoad*/,
+                                    tHi, ARMAMode1_RI(rA, 4)));
+      addInstr(env, ARMInstr_LdSt32(ARMcc_AL, True/*isLoad*/,
+                                    tLo, ARMAMode1_RI(rA, 0)));
       *rHi = tHi;
       *rLo = tLo;
       return;
@@ -1871,8 +1869,8 @@
       ARMAMode1* am4 = ARMAMode1_RI(hregARM_R8(), e->Iex.Get.offset + 4);
       HReg tHi = newVRegI(env);
       HReg tLo = newVRegI(env);
-      addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tHi, am4));
-      addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tLo, am0));
+      addInstr(env, ARMInstr_LdSt32(ARMcc_AL, True/*isLoad*/, tHi, am4));
+      addInstr(env, ARMInstr_LdSt32(ARMcc_AL, True/*isLoad*/, tLo, am0));
       *rHi = tHi;
       *rLo = tLo;
       return;
@@ -4267,13 +4265,17 @@
 
                /* Store the less significant 64 bits */
                iselInt64Expr(&w1, &w0, env, e->Iex.Binop.arg2);
-               addInstr(env, ARMInstr_LdSt32(False/*store*/, w0, sp_0));
-               addInstr(env, ARMInstr_LdSt32(False/*store*/, w1, sp_4));
+               addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*store*/,
+                                             w0, sp_0));
+               addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*store*/,
+                                             w1, sp_4));
          
                /* Store the more significant 64 bits */
                iselInt64Expr(&w3, &w2, env, e->Iex.Binop.arg1);
-               addInstr(env, ARMInstr_LdSt32(False/*store*/, w2, sp_8));
-               addInstr(env, ARMInstr_LdSt32(False/*store*/, w3, sp_12));
+               addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*store*/,
+                                             w2, sp_8));
+               addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*store*/,
+                                             w3, sp_12));
          
                 /* Load result back from stack. */
                 addInstr(env, ARMInstr_NLdStQ(True/*load*/, res,
@@ -5651,20 +5653,21 @@
       if (tyd == Ity_I32) {
          HReg       rD = iselIntExpr_R(env, stmt->Ist.Store.data);
          ARMAMode1* am = iselIntExpr_AMode1(env, stmt->Ist.Store.addr);
-         addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rD, am));
+         addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*!isLoad*/, rD, am));
          return;
       }
       if (tyd == Ity_I16) {
          HReg       rD = iselIntExpr_R(env, stmt->Ist.Store.data);
          ARMAMode2* am = iselIntExpr_AMode2(env, stmt->Ist.Store.addr);
-         addInstr(env, ARMInstr_LdSt16(False/*!isLoad*/,
+         addInstr(env, ARMInstr_LdSt16(ARMcc_AL,
+                                       False/*!isLoad*/,
                                        False/*!isSignedLoad*/, rD, am));
          return;
       }
       if (tyd == Ity_I8) {
          HReg       rD = iselIntExpr_R(env, stmt->Ist.Store.data);
          ARMAMode1* am = iselIntExpr_AMode1(env, stmt->Ist.Store.addr);
-         addInstr(env, ARMInstr_LdSt8U(False/*!isLoad*/, rD, am));
+         addInstr(env, ARMInstr_LdSt8U(ARMcc_AL, False/*!isLoad*/, rD, am));
          return;
       }
       if (tyd == Ity_I64) {
@@ -5676,9 +5679,9 @@
             HReg rDhi, rDlo, rA;
             iselInt64Expr(&rDhi, &rDlo, env, stmt->Ist.Store.data);
             rA = iselIntExpr_R(env, stmt->Ist.Store.addr);
-            addInstr(env, ARMInstr_LdSt32(False/*!load*/, rDhi,
+            addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*!load*/, rDhi,
                                           ARMAMode1_RI(rA,4)));
-            addInstr(env, ARMInstr_LdSt32(False/*!load*/, rDlo,
+            addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*!load*/, rDlo,
                                           ARMAMode1_RI(rA,0)));
          }
          return;
@@ -5705,6 +5708,88 @@
       break;
    }
 
+   /* --------- CONDITIONAL STORE --------- */
+   /* conditional little-endian write to memory */
+   case Ist_StoreG: {
+      IRStoreG* sg   = stmt->Ist.StoreG.details;
+      IRType    tya  = typeOfIRExpr(env->type_env, sg->addr);
+      IRType    tyd  = typeOfIRExpr(env->type_env, sg->data);
+      IREndness end  = sg->end;
+
+      if (tya != Ity_I32 || end != Iend_LE) 
+         goto stmt_fail;
+
+      switch (tyd) {
+         case Ity_I8:
+         case Ity_I32: {
+            HReg        rD = iselIntExpr_R(env, sg->data);
+            ARMAMode1*  am = iselIntExpr_AMode1(env, sg->addr);
+            ARMCondCode cc = iselCondCode(env, sg->guard);
+            addInstr(env, (tyd == Ity_I32 ? ARMInstr_LdSt32 : ARMInstr_LdSt8U)
+                             (cc, False/*!isLoad*/, rD, am));
+            return;
+         }
+         case Ity_I16: {
+            HReg        rD = iselIntExpr_R(env, sg->data);
+            ARMAMode2*  am = iselIntExpr_AMode2(env, sg->addr);
+            ARMCondCode cc = iselCondCode(env, sg->guard);
+            addInstr(env, ARMInstr_LdSt16(cc, 
+                                          False/*!isLoad*/,
+                                          False/*!isSignedLoad*/, rD, am));
+            return;
+         }
+         default:
+            break;
+      }
+      break;
+   }
+
+   /* --------- CONDITIONAL LOAD --------- */
+   /* conditional little-endian load from memory */
+   case Ist_LoadG: {
+      IRLoadG*  lg   = stmt->Ist.LoadG.details;
+      IRType    tya  = typeOfIRExpr(env->type_env, lg->addr);
+      IREndness end  = lg->end;
+
+      if (tya != Ity_I32 || end != Iend_LE) 
+         goto stmt_fail;
+
+      switch (lg->cvt) {
+         case ILGop_8Uto32:
+         case ILGop_Ident32: {
+            HReg        rAlt = iselIntExpr_R(env, lg->alt);
+            ARMAMode1*  am   = iselIntExpr_AMode1(env, lg->addr);
+            HReg        rD   = lookupIRTemp(env, lg->dst);
+            addInstr(env, mk_iMOVds_RR(rD, rAlt));
+            ARMCondCode cc   = iselCondCode(env, lg->guard);
+            addInstr(env, (lg->cvt == ILGop_Ident32 ? ARMInstr_LdSt32
+                                                    : ARMInstr_LdSt8U)
+                             (cc, True/*isLoad*/, rD, am));
+            return;
+         }
+         case ILGop_16Sto32:
+         case ILGop_16Uto32:
+         case ILGop_8Sto32: {
+            HReg        rAlt = iselIntExpr_R(env, lg->alt);
+            ARMAMode2*  am   = iselIntExpr_AMode2(env, lg->addr);
+            HReg        rD   = lookupIRTemp(env, lg->dst);
+            addInstr(env, mk_iMOVds_RR(rD, rAlt));
+            ARMCondCode cc   = iselCondCode(env, lg->guard);
+            if (lg->cvt == ILGop_8Sto32) {
+               addInstr(env, ARMInstr_Ld8S(cc, rD, am));
+            } else {
+               vassert(lg->cvt == ILGop_16Sto32 || lg->cvt == ILGop_16Uto32);
+               Bool sx = lg->cvt == ILGop_16Sto32;
+               addInstr(env, ARMInstr_LdSt16(cc, True/*isLoad*/, sx, rD, am));
+            }
+            return;
+         }
+         default:
+            break;
+      }
+      break;
+   }
+
    /* --------- PUT --------- */
    /* write guest state, fixed offset */
    case Ist_Put: {
@@ -5713,7 +5798,7 @@
        if (tyd == Ity_I32) {
            HReg       rD = iselIntExpr_R(env, stmt->Ist.Put.data);
            ARMAMode1* am = ARMAMode1_RI(hregARM_R8(), stmt->Ist.Put.offset);
-           addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rD, am));
+           addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*!isLoad*/, rD, am));
            return;
        }
        if (tyd == Ity_I64) {
@@ -5730,8 +5815,10 @@
              ARMAMode1* am4 = ARMAMode1_RI(hregARM_R8(),
                                            stmt->Ist.Put.offset + 4);
              iselInt64Expr(&rDhi, &rDlo, env, stmt->Ist.Put.data);
-             addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rDhi, am4));
-             addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rDlo, am0));
+             addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*!isLoad*/,
+                                           rDhi, am4));
+             addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*!isLoad*/,
+                                           rDlo, am0));
           }
           return;
        }
@@ -5762,25 +5849,6 @@
        break;
    }
 
-//zz   /* --------- Indexed PUT --------- */
-//zz   /* write guest state, run-time offset */
-//zz   case Ist_PutI: {
-//zz      ARMAMode2* am2
-//zz           = genGuestArrayOffset(
-//zz               env, stmt->Ist.PutI.descr, 
-//zz               stmt->Ist.PutI.ix, stmt->Ist.PutI.bias );
-//zz       
-//zz       IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data);
-//zz       
-//zz       if (tyd == Ity_I8) {
-//zz           HReg reg = iselIntExpr_R(env, stmt->Ist.PutI.data);
-//zz           addInstr(env, ARMInstr_StoreB(reg, am2));
-//zz           return;
-//zz       }
-//zz// CAB: Ity_I32, Ity_I16 ?
-//zz       break;
-//zz   }
-
    /* --------- TMP --------- */
    /* assign value to temporary */
    case Ist_WrTmp: {
@@ -5839,7 +5907,6 @@
    /* --------- Call to DIRTY helper --------- */
    /* call complex ("dirty") helper function */
    case Ist_Dirty: {
-      IRType   retty;
       IRDirty* d = stmt->Ist.Dirty.details;
       Bool     passBBP = False;
 
@@ -5848,8 +5915,31 @@
 
       passBBP = toBool(d->nFxState > 0 && d->needsBBP);
 
-      /* Marshal args, do the call, clear stack. */
-      Bool ok = doHelperCall( env, passBBP, d->guard, d->cee, d->args );
+      /* Figure out the return type, if any. */
+      IRType retty = Ity_INVALID;
+      if (d->tmp != IRTemp_INVALID)
+         retty = typeOfIRTemp(env->type_env, d->tmp);
+
+      /* Marshal args, do the call, clear stack, set the return value
+         to 0x555..555 if this is a conditional call that returns a
+         value and the call is skipped.  We need to set the ret-loc
+         correctly in order to implement the IRDirty semantics that
+         the return value is 0x555..555 if the call doesn't happen. */
+      RetLoc rloc = RetLocINVALID;
+      switch (retty) {
+         case Ity_INVALID: /* function doesn't return anything */
+            rloc = RetLocNone; break;
+         case Ity_I64:
+            rloc = RetLoc2Int; break;
+         case Ity_I32: case Ity_I16: case Ity_I8:
+            rloc = RetLocInt; break;
+         default:
+            break;
+      }
+      if (rloc == RetLocINVALID)
+         break; /* will go to stmt_fail: */
+
+      Bool ok = doHelperCall( env, passBBP, d->guard, d->cee, d->args, rloc );
       if (!ok)
          break; /* will go to stmt_fail: */
 
@@ -5858,8 +5948,6 @@
          /* No return value.  Nothing to do. */
          return;
 
-      retty = typeOfIRTemp(env->type_env, d->tmp);
-
       if (retty == Ity_I64) {
          if (env->hwcaps & VEX_HWCAPS_ARM_NEON) {
             HReg tmp = lookupIRTemp(env, d->tmp);
@@ -6174,6 +6262,9 @@
    /* sanity ... */
    vassert(arch_host == VexArchARM);
 
+   /* guard against unexpected space regressions */
+   vassert(sizeof(ARMInstr) <= 28);
+
    /* hwcaps should not change from one ISEL call to another. */
    arm_hwcaps = hwcaps_host; // JRS 2012 Mar 31: FIXME (RM)