Blame SOURCES/valgrind-3.14.0-ppc-instr-new-IROps.patch

560544
commit 97d336b79e36f6c99d8b07f49ebc9b780e6df84e
560544
Author: Julian Seward <jseward@acm.org>
560544
Date:   Tue Nov 20 11:07:37 2018 +0100
560544
560544
    Add ppc host-side isel and instruction support for IROps added in previous commit.
560544
    
560544
    VEX/priv/host_ppc_defs.c, VEX/priv/host_ppc_defs.h:
560544
    
560544
    Dont emit cnttz{w,d}.  We may need them on a target which doesn't support
560544
    them.  Instead we can generate a fairly reasonable alternative sequence with
560544
    cntlz{w,d} instead.
560544
    
560544
    Add support for emitting popcnt{w,d}.
560544
    
560544
    VEX/priv/host_ppc_isel.c
560544
    
560544
    Add support for: Iop_ClzNat32 Iop_ClzNat64
560544
    
560544
    Redo support for: Iop_Ctz{32,64} and their Nat equivalents, so as to not use
560544
    cnttz{w,d}, as mentioned above.
560544
    
560544
    Add support for: Iop_PopCount64 Iop_PopCount32 Iop_Reverse8sIn32_x1
560544
560544
diff --git a/VEX/priv/host_ppc_defs.c b/VEX/priv/host_ppc_defs.c
560544
index b073c1d..f4b52e4 100644
560544
--- a/VEX/priv/host_ppc_defs.c
560544
+++ b/VEX/priv/host_ppc_defs.c
560544
@@ -501,9 +501,9 @@ const HChar* showPPCUnaryOp ( PPCUnaryOp op ) {
560544
    case Pun_NEG:   return "neg";
560544
    case Pun_CLZ32: return "cntlzw";
560544
    case Pun_CLZ64: return "cntlzd";
560544
-   case Pun_CTZ32: return "cnttzw";
560544
-   case Pun_CTZ64: return "cnttzd";
560544
    case Pun_EXTSW: return "extsw";
560544
+   case Pun_POP32: return "popcntw";
560544
+   case Pun_POP64: return "popcntd";
560544
    default: vpanic("showPPCUnaryOp");
560544
    }
560544
 }
560544
@@ -4265,20 +4265,19 @@ Int emit_PPCInstr ( /*MB_MOD*/Bool* is_profInc,
560544
          vassert(mode64);
560544
          p = mkFormX(p, 31, r_src, r_dst, 0, 58, 0, endness_host);
560544
          break;
560544
-      case Pun_CTZ32:  // cnttzw r_dst, r_src
560544
-         /* Note oder of src and dst is backwards from normal */
560544
-         p = mkFormX(p, 31, r_src, r_dst, 0, 538, 0, endness_host);
560544
-         break;
560544
-      case Pun_CTZ64:  // cnttzd r_dst, r_src
560544
-         /* Note oder of src and dst is backwards from normal */
560544
-         vassert(mode64);
560544
-         p = mkFormX(p, 31, r_src, r_dst, 0, 570, 0, endness_host);
560544
-         break;
560544
       case Pun_EXTSW:  // extsw r_dst, r_src
560544
          vassert(mode64);
560544
          p = mkFormX(p, 31, r_src, r_dst, 0, 986, 0, endness_host);
560544
          break;
560544
-      default: goto bad;
560544
+      case Pun_POP32:  // popcntw r_dst, r_src
560544
+         p = mkFormX(p, 31, r_src, r_dst, 0, 378, 0, endness_host);
560544
+         break;
560544
+      case Pun_POP64:  // popcntd r_dst, r_src
560544
+         vassert(mode64);
560544
+         p = mkFormX(p, 31, r_src, r_dst, 0, 506, 0, endness_host);
560544
+         break;
560544
+      default:
560544
+         goto bad;
560544
       }
560544
       goto done;
560544
    }
560544
diff --git a/VEX/priv/host_ppc_defs.h b/VEX/priv/host_ppc_defs.h
560544
index 17baff5..321fba9 100644
560544
--- a/VEX/priv/host_ppc_defs.h
560544
+++ b/VEX/priv/host_ppc_defs.h
560544
@@ -291,9 +291,9 @@ typedef
560544
       Pun_NOT,
560544
       Pun_CLZ32,
560544
       Pun_CLZ64,
560544
-      Pun_CTZ32,
560544
-      Pun_CTZ64,
560544
-      Pun_EXTSW
560544
+      Pun_EXTSW,
560544
+      Pun_POP32, // popcntw
560544
+      Pun_POP64  // popcntd
560544
    }
560544
    PPCUnaryOp;
560544
 
560544
diff --git a/VEX/priv/host_ppc_isel.c b/VEX/priv/host_ppc_isel.c
560544
index 6bdb5f7..5242176 100644
560544
--- a/VEX/priv/host_ppc_isel.c
560544
+++ b/VEX/priv/host_ppc_isel.c
560544
@@ -2065,12 +2065,15 @@ static HReg iselWordExpr_R_wrk ( ISelEnv* env, const IRExpr* e,
560544
             return r_dst;
560544
          }
560544
          break;
560544
-      case Iop_Clz32:
560544
-      case Iop_Clz64: {
560544
+
560544
+      case Iop_Clz32: case Iop_ClzNat32:
560544
+      case Iop_Clz64: case Iop_ClzNat64: {
560544
+         // cntlz is available even in the most basic (earliest) ppc
560544
+         // variants, so it's safe to generate it unconditionally.
560544
          HReg r_src, r_dst;
560544
-         PPCUnaryOp op_clz = (op_unop == Iop_Clz32) ? Pun_CLZ32 :
560544
-                                                      Pun_CLZ64;
560544
-         if (op_unop == Iop_Clz64 && !mode64)
560544
+         PPCUnaryOp op_clz = (op_unop == Iop_Clz32 || op_unop == Iop_ClzNat32)
560544
+                                ? Pun_CLZ32 : Pun_CLZ64;
560544
+         if ((op_unop == Iop_Clz64 || op_unop == Iop_ClzNat64) && !mode64)
560544
             goto irreducible;
560544
          /* Count leading zeroes. */
560544
          r_dst = newVRegI(env);
560544
@@ -2079,18 +2082,133 @@ static HReg iselWordExpr_R_wrk ( ISelEnv* env, const IRExpr* e,
560544
          return r_dst;
560544
       }
560544
 
560544
-      case Iop_Ctz32:
560544
-      case Iop_Ctz64: {
560544
-         HReg r_src, r_dst;
560544
-         PPCUnaryOp op_clz = (op_unop == Iop_Ctz32) ? Pun_CTZ32 :
560544
-                                                      Pun_CTZ64;
560544
-         if (op_unop == Iop_Ctz64 && !mode64)
560544
-            goto irreducible;
560544
-         /* Count trailing zeroes. */
560544
-         r_dst = newVRegI(env);
560544
-         r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
560544
-         addInstr(env, PPCInstr_Unary(op_clz,r_dst,r_src));
560544
-         return r_dst;
560544
+      //case Iop_Ctz32:
560544
+      case Iop_CtzNat32:
560544
+      //case Iop_Ctz64:
560544
+      case Iop_CtzNat64:
560544
+      {
560544
+         // Generate code using Clz, because we can't assume the host has
560544
+         // Ctz.  In particular, part of the fix for bug 386945 involves
560544
+         // creating a Ctz in ir_opt.c from smaller fragments.
560544
+         PPCUnaryOp op_clz = Pun_CLZ64;
560544
+         Int WS = 64;
560544
+         if (op_unop == Iop_Ctz32 || op_unop == Iop_CtzNat32) {
560544
+            op_clz = Pun_CLZ32;
560544
+            WS = 32;
560544
+         }
560544
+         /* Compute ctz(arg) = wordsize - clz(~arg & (arg - 1)), thusly:
560544
+            t1 = arg - 1
560544
+            t2 = not arg
560544
+            t2 = t2 & t1
560544
+            t2 = clz t2
560544
+            t1 = WS
560544
+            t2 = t1 - t2
560544
+            // result in t2
560544
+         */
560544
+         HReg arg = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
560544
+         HReg t1 = newVRegI(env);
560544
+         HReg t2 = newVRegI(env);
560544
+         addInstr(env, PPCInstr_Alu(Palu_SUB, t1, arg, PPCRH_Imm(True, 1)));
560544
+         addInstr(env, PPCInstr_Unary(Pun_NOT, t2, arg));
560544
+         addInstr(env, PPCInstr_Alu(Palu_AND, t2, t2, PPCRH_Reg(t1)));
560544
+         addInstr(env, PPCInstr_Unary(op_clz, t2, t2));
560544
+         addInstr(env, PPCInstr_LI(t1, WS, False/*!64-bit imm*/));
560544
+         addInstr(env, PPCInstr_Alu(Palu_SUB, t2, t1, PPCRH_Reg(t2)));
560544
+         return t2;
560544
+      }
560544
+
560544
+      case Iop_PopCount64: {
560544
+         // popcnt{x,d} is only available in later arch revs (ISA 3.0,
560544
+         // maybe) so it's not really correct to emit it here without a caps
560544
+         // check for the host.
560544
+         if (mode64) {
560544
+            HReg r_dst = newVRegI(env);
560544
+            HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
560544
+            addInstr(env, PPCInstr_Unary(Pun_POP64, r_dst, r_src));
560544
+            return r_dst;
560544
+         }
560544
+         // We don't expect to be required to handle this in 32-bit mode.
560544
+         break;
560544
+      }
560544
+
560544
+      case Iop_PopCount32: {
560544
+         // Similar comment as for Ctz just above applies -- we really
560544
+         // should have a caps check here.
560544
+
560544
+        HReg r_dst = newVRegI(env);
560544
+        // This actually generates popcntw, which in 64 bit mode does a
560544
+        // 32-bit count individually for both low and high halves of the
560544
+        // word.  Per the comment at the top of iselIntExpr_R, in the 64
560544
+        // bit mode case, the user of this result is required to ignore
560544
+        // the upper 32 bits of the result.  In 32 bit mode this is all
560544
+        // moot.  It is however unclear from the PowerISA 3.0 docs that
560544
+        // the instruction exists in 32 bit mode; however our own front
560544
+        // end (guest_ppc_toIR.c) accepts it, so I guess it does exist.
560544
+        HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
560544
+        addInstr(env, PPCInstr_Unary(Pun_POP32, r_dst, r_src));
560544
+        return r_dst;
560544
+      }
560544
+
560544
+      case Iop_Reverse8sIn32_x1: {
560544
+         // A bit of a mouthful, but simply .. 32-bit byte swap.
560544
+         // This is pretty rubbish code.  We could do vastly better if
560544
+         // rotates, and better, rotate-inserts, were allowed.  Note that
560544
+         // even on a 64 bit target, the right shifts must be done as 32-bit
560544
+         // so as to introduce zero bits in the right places.  So it seems
560544
+         // simplest to do the whole sequence in 32-bit insns.
560544
+         /*
560544
+            r     = <argument>  // working temporary, initial byte order ABCD
560544
+            Mask  = 00FF00FF
560544
+            nMask = not Mask
560544
+            tHi   = and r, Mask
560544
+            tHi   = shl tHi, 8
560544
+            tLo   = and r, nMask
560544
+            tLo   = shr tLo, 8
560544
+            r     = or tHi, tLo  // now r has order BADC
560544
+            and repeat for 16 bit chunks ..
560544
+            Mask  = 0000FFFF
560544
+            nMask = not Mask
560544
+            tHi   = and r, Mask
560544
+            tHi   = shl tHi, 16
560544
+            tLo   = and r, nMask
560544
+            tLo   = shr tLo, 16
560544
+            r     = or tHi, tLo  // now r has order DCBA
560544
+         */
560544
+         HReg r_src  = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
560544
+         HReg rr     = newVRegI(env);
560544
+         HReg rMask  = newVRegI(env);
560544
+         HReg rnMask = newVRegI(env);
560544
+         HReg rtHi   = newVRegI(env);
560544
+         HReg rtLo   = newVRegI(env);
560544
+         // Copy r_src since we need to modify it
560544
+         addInstr(env, mk_iMOVds_RR(rr, r_src));
560544
+         // Swap within 16-bit lanes
560544
+         addInstr(env, PPCInstr_LI(rMask, 0x00FF00FFULL,
560544
+                                   False/* !64bit imm*/));
560544
+         addInstr(env, PPCInstr_Unary(Pun_NOT, rnMask, rMask));
560544
+         addInstr(env, PPCInstr_Alu(Palu_AND, rtHi, rr, PPCRH_Reg(rMask)));
560544
+         addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32 bit shift*/,
560544
+                                     rtHi, rtHi,
560544
+                                     PPCRH_Imm(False/*!signed imm*/, 8)));
560544
+         addInstr(env, PPCInstr_Alu(Palu_AND, rtLo, rr, PPCRH_Reg(rnMask)));
560544
+         addInstr(env, PPCInstr_Shft(Pshft_SHR, True/*32 bit shift*/,
560544
+                                     rtLo, rtLo,
560544
+                                     PPCRH_Imm(False/*!signed imm*/, 8)));
560544
+         addInstr(env, PPCInstr_Alu(Palu_OR, rr, rtHi, PPCRH_Reg(rtLo)));
560544
+         // And now swap the two 16-bit chunks
560544
+         addInstr(env, PPCInstr_LI(rMask, 0x0000FFFFULL,
560544
+                                   False/* !64bit imm*/));
560544
+         addInstr(env, PPCInstr_Unary(Pun_NOT, rnMask, rMask));
560544
+         addInstr(env, PPCInstr_Alu(Palu_AND, rtHi, rr, PPCRH_Reg(rMask)));
560544
+         addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32 bit shift*/,
560544
+                                     rtHi, rtHi,
560544
+                                     PPCRH_Imm(False/*!signed imm*/, 16)));
560544
+         addInstr(env, PPCInstr_Alu(Palu_AND, rtLo, rr, PPCRH_Reg(rnMask)));
560544
+         addInstr(env, PPCInstr_Shft(Pshft_SHR, True/*32 bit shift*/,
560544
+                                     rtLo, rtLo,
560544
+                                     PPCRH_Imm(False/*!signed imm*/, 16)));
560544
+         addInstr(env, PPCInstr_Alu(Palu_OR, rr, rtHi, PPCRH_Reg(rtLo)));
560544
+         return rr;
560544
       }
560544
 
560544
       case Iop_Left8: