]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
mips64: Support for Cavium MIPS Octeon Atomic and Count Instructions.
authorDejan Jevtic <dejan.jevtic@valgrind.org>
Wed, 4 Jun 2014 11:28:07 +0000 (11:28 +0000)
committerDejan Jevtic <dejan.jevtic@valgrind.org>
Wed, 4 Jun 2014 11:28:07 +0000 (11:28 +0000)
Implement Cavium MIPS specific instructions:
baddu, pop, dpop, saa, saad, laa, laad, lai, laid, lad, ladd, law, lawd,
las, lasd, lac, lacd

Fixes BZ #327223.

git-svn-id: svn://svn.valgrind.org/vex/trunk@2865

VEX/priv/guest_mips_toIR.c
VEX/priv/host_mips_defs.c
VEX/priv/host_mips_defs.h
VEX/priv/host_mips_isel.c

index 92059ede0c6d559f3bf7bf15501352217fcc50db..d8bdfeb3607d69aa88220ee4e4e50927d1379eaa 100644 (file)
@@ -2170,6 +2170,62 @@ static Bool dis_instr_branch ( UInt theInstr, DisResult * dres,
 /*********************************************************/
 /*---         Cavium Specific Instructions            ---*/
 /*********************************************************/
+
+/* Convenience function to yield to thread scheduler */
+static void jump_back(IRExpr *condition)
+{
+   stmt( IRStmt_Exit(condition,
+                     Ijk_Yield,
+                     IRConst_U64( guest_PC_curr_instr ),
+                     OFFB_PC) );
+}
+
+/* Based on s390_irgen_load_and_add32. */
+static void mips_irgen_load_and_add32(IRTemp op1addr, IRTemp new_val,
+                                      UChar rd, Bool putIntoRd)
+{
+   IRCAS *cas;
+   IRTemp old_mem = newTemp(Ity_I32);
+   IRTemp expd    = newTemp(Ity_I32);
+
+   assign(expd, load(Ity_I32, mkexpr(op1addr)));
+
+   cas = mkIRCAS(IRTemp_INVALID, old_mem,
+                 Iend_LE, mkexpr(op1addr),
+                 NULL, mkexpr(expd), /* expected value */
+                 NULL, mkexpr(new_val)  /* new value */);
+   stmt(IRStmt_CAS(cas));
+
+   /* If old_mem contains the expected value, then the CAS succeeded.
+      Otherwise, it did not */
+   jump_back(binop(Iop_CmpNE32, mkexpr(old_mem), mkexpr(expd)));
+   if (putIntoRd)
+      putIReg(rd, mkWidenFrom32(Ity_I64, mkexpr(old_mem), True));
+}
+
+/* Based on s390_irgen_load_and_add64. */
+static void mips_irgen_load_and_add64(IRTemp op1addr, IRTemp new_val,
+                                      UChar rd, Bool putIntoRd)
+{
+   IRCAS *cas;
+   IRTemp old_mem = newTemp(Ity_I64);
+   IRTemp expd    = newTemp(Ity_I64);
+
+   assign(expd, load(Ity_I64, mkexpr(op1addr)));
+
+   cas = mkIRCAS(IRTemp_INVALID, old_mem,
+                 Iend_LE, mkexpr(op1addr),
+                 NULL, mkexpr(expd), /* expected value */
+                 NULL, mkexpr(new_val)  /* new value */);
+   stmt(IRStmt_CAS(cas));
+
+   /* If old_mem contains the expected value, then the CAS succeeded.
+      Otherwise, it did not */
+   jump_back(binop(Iop_CmpNE64, mkexpr(old_mem), mkexpr(expd)));
+   if (putIntoRd)
+      putIReg(rd, mkexpr(old_mem));
+}
+
 static Bool dis_instr_CVM ( UInt theInstr )
 {
    UChar  opc2     = get_function(theInstr);
@@ -2177,7 +2233,7 @@ static Bool dis_instr_CVM ( UInt theInstr )
    UChar  regRs    = get_rs(theInstr);
    UChar  regRt    = get_rt(theInstr);
    UChar  regRd    = get_rd(theInstr);
-   UInt   imm     = get_imm(theInstr);
+   UInt   imm      = get_imm(theInstr);
    UChar  lenM1    = get_msb(theInstr);
    UChar  p        = get_lsb(theInstr);
    IRType ty       = mode64? Ity_I64 : Ity_I32;
@@ -2188,8 +2244,8 @@ static Bool dis_instr_CVM ( UInt theInstr )
    UInt size;
    assign(tmpRs, getIReg(regRs));
 
-   switch(opc1){
-      case 0x1C:  {
+   switch(opc1) {
+      case 0x1C: {
          switch(opc2) { 
             case 0x03: {  /* DMUL rd, rs, rt */
                DIP("dmul r%d, r%d, r%d", regRd, regRs, regRt);
@@ -2199,6 +2255,277 @@ static Bool dis_instr_CVM ( UInt theInstr )
                break;
             }
 
+            case 0x18: {  /* Store Atomic Add Word - SAA; Cavium OCTEON */
+               DIP("saa r%u, (r%u)", regRt, regRs);
+               IRTemp addr = newTemp(Ity_I64);
+               IRTemp new  = newTemp(Ity_I32);
+               assign (addr, getIReg(regRs));
+               assign(new, binop(Iop_Add32,
+                                 load(Ity_I32, mkexpr(addr)),
+                                 mkNarrowTo32(ty, getIReg(regRt))));
+               mips_irgen_load_and_add32(addr, new, 0, False);
+               break;
+            }
+
+            /* Store Atomic Add Doubleword - SAAD; Cavium OCTEON */
+            case 0x19: {
+               DIP( "saad r%u, (r%u)", regRt, regRs);
+               IRTemp addr = newTemp(Ity_I64);
+               IRTemp new  = newTemp(Ity_I64);
+               assign (addr, getIReg(regRs));
+               assign(new, binop(Iop_Add64,
+                                 load(Ity_I64, mkexpr(addr)),
+                                 getIReg(regRt)));
+               mips_irgen_load_and_add64(addr, new, 0, False);
+               break;
+            }
+
+            /* LAI, LAID, LAD, LADD, LAS, LASD,
+               LAC, LACD, LAA, LAAD, LAW, LAWD */
+            case 0x1f: {
+               UInt opc3 = get_sa(theInstr);
+               IRTemp addr = newTemp(Ity_I64);
+               switch (opc3) {
+                  /* Load Atomic Increment Word - LAI; Cavium OCTEON2 */
+                  case 0x02: {
+                     DIP("lai r%u,(r%u)\n", regRd, regRs);
+                     IRTemp new  = newTemp(Ity_I32);
+                     assign(addr, getIReg(regRs));
+                     assign(new, binop(Iop_Add32,
+                                       load(Ity_I32, mkexpr(addr)),
+                                       mkU32(1)));
+                     mips_irgen_load_and_add32(addr, new, regRd, True);
+                     break;
+                  }
+                  /* Load Atomic Increment Doubleword - LAID; Cavium OCTEON2 */
+                  case 0x03: {
+                     DIP("laid r%u,(r%u)\n", regRd, regRs);
+                     IRTemp new  = newTemp(Ity_I64);
+                     assign(addr, getIReg(regRs));
+                     assign(new, binop(Iop_Add64,
+                                       load(Ity_I64, mkexpr(addr)),
+                                       mkU64(1)));
+                     mips_irgen_load_and_add64(addr, new, regRd, True);
+                     break;
+                  }
+                  /* Load Atomic Decrement Word - LAD; Cavium OCTEON2 */
+                  case 0x06: {
+                     DIP("lad r%u,(r%u)\n", regRd, regRs);
+                     IRTemp new  = newTemp(Ity_I32);
+                     assign(addr, getIReg(regRs));
+                     assign(new, binop(Iop_Sub32,
+                                       load(Ity_I32, mkexpr(addr)),
+                                       mkU32(1)));
+                     mips_irgen_load_and_add32(addr, new, regRd, True);
+                     break;
+                  }
+                  /* Load Atomic Decrement Doubleword - LADD; Cavium OCTEON2 */
+                  case 0x07: {
+                     DIP("ladd r%u,(r%u)\n", regRd, regRs);
+                     IRTemp new  = newTemp(Ity_I64);
+                     assign (addr, getIReg(regRs));
+                     assign(new, binop(Iop_Sub64,
+                                       load(Ity_I64, mkexpr(addr)),
+                                       mkU64(1)));
+                     mips_irgen_load_and_add64(addr, new, regRd, True);
+                     break;
+                  }
+                  /* Load Atomic Set Word - LAS; Cavium OCTEON2 */
+                  case 0x0a: {
+                     DIP("las r%u,(r%u)\n", regRd, regRs);
+                     IRTemp new  = newTemp(Ity_I32);
+                     assign(addr, getIReg(regRs));
+                     assign(new, mkU32(0xffffffff));
+                     mips_irgen_load_and_add32(addr, new, regRd, True);
+                     break;
+                  }
+                  /* Load Atomic Set Doubleword - LASD; Cavium OCTEON2 */
+                  case 0x0b: {
+                     DIP("lasd r%u,(r%u)\n", regRd, regRs);
+                     IRTemp new  = newTemp(Ity_I64);
+                     assign (addr, getIReg(regRs));
+                     assign(new, mkU64(0xffffffffffffffff));
+                     mips_irgen_load_and_add64(addr, new, regRd, True);
+                     break;
+                  }
+                  /* Load Atomic Clear Word - LAC; Cavium OCTEON2 */
+                  case 0x0e: {
+                     DIP("lac r%u,(r%u)\n", regRd, regRs);
+                     IRTemp new  = newTemp(Ity_I32);
+                     assign (addr, getIReg(regRs));
+                     assign(new, mkU32(0));
+                     mips_irgen_load_and_add32(addr, new, regRd, True);
+                     break;
+                  }
+                  /* Load Atomic Clear Doubleword - LACD; Cavium OCTEON2 */
+                  case 0x0f: {
+                     DIP("lacd r%u,(r%u)\n", regRd, regRs);
+                     IRTemp new  = newTemp(Ity_I64);
+                     assign(addr, getIReg(regRs));
+                     assign(new, mkU64(0));
+                     mips_irgen_load_and_add64(addr, new, regRd, True);
+                     break;
+                  }
+                  /* Load Atomic Add Word - LAA; Cavium OCTEON2 */
+                  case 0x12: {
+                     DIP("laa r%u,(r%u),r%u\n", regRd, regRs, regRt);
+                     IRTemp new  = newTemp(Ity_I32);
+                     assign(addr, getIReg(regRs));
+                     assign(new, binop(Iop_Add32,
+                                       load(Ity_I32, mkexpr(addr)),
+                                       mkNarrowTo32(ty, getIReg(regRt))));
+                     mips_irgen_load_and_add32(addr, new, regRd, True);
+                     break;
+                  }
+                  /* Load Atomic Add Doubleword - LAAD; Cavium OCTEON2 */
+                  case 0x13: {
+                     DIP("laad r%u,(r%u),r%u\n", regRd, regRs, regRt);
+                     IRTemp new  = newTemp(Ity_I64);
+                     assign (addr, getIReg(regRs));
+                     assign(new, binop(Iop_Add64,
+                                       load(Ity_I64, mkexpr(addr)),
+                                       getIReg(regRt)));
+                     mips_irgen_load_and_add64(addr, new, regRd, True);
+                     break;
+                  }
+                  /* Load Atomic Swap Word - LAW; Cavium OCTEON2 */
+                  case 0x16: {
+                     DIP("law r%u,(r%u)\n", regRd, regRs);
+                     IRTemp new  = newTemp(Ity_I32);
+                     assign(addr, getIReg(regRs));
+                     assign(new, mkNarrowTo32(ty, getIReg(regRt)));
+                     mips_irgen_load_and_add32(addr, new, regRd, True);
+                     break;
+                  }
+                  /* Load Atomic Swap Doubleword - LAWD; Cavium OCTEON2 */
+                  case 0x17: {
+                     DIP("lawd r%u,(r%u)\n", regRd, regRs);
+                     IRTemp new  = newTemp(Ity_I64);
+                     assign(addr, getIReg(regRs));
+                     assign(new, getIReg(regRt));
+                     mips_irgen_load_and_add64(addr, new, regRd, True);
+                     break;
+                  }
+                  default:
+                     vex_printf("Unknown laxx instruction, opc3=0x%x\n", opc3);
+                     vex_printf("Instruction=0x%08x\n", theInstr);
+                     return False;
+               }
+               break;
+            }
+
+            /* Unsigned Byte Add - BADDU rd, rs, rt; Cavium OCTEON */
+            case 0x28: {
+               DIP("BADDU r%d, r%d, r%d", regRs, regRt, regRd);
+               IRTemp t0 = newTemp(Ity_I8);
+               assign(t0, binop(Iop_Add8,
+                                mkNarrowTo8(ty, getIReg(regRs)),
+                                mkNarrowTo8(ty, getIReg(regRt))));
+               if (mode64)
+                  putIReg(regRd, binop(mkSzOp(ty, Iop_And8),
+                                       unop(Iop_8Uto64, mkexpr(t0)),
+                                       mkSzImm(ty, 0xFF)));
+               else
+                  putIReg(regRd, binop(mkSzOp(ty, Iop_And8),
+                                       unop(Iop_8Uto32, mkexpr(t0)),
+                                       mkSzImm(ty, 0xFF)));
+               break;
+            }
+            case 0x2c: {  /* Count Ones in a Word - POP; Cavium OCTEON */
+               int i, shift[5];
+               IRTemp mask[5];
+               IRTemp old = newTemp(ty);
+               IRTemp nyu = IRTemp_INVALID;
+               assign(old, getIReg(regRs));
+               DIP("pop r%d, r%d", regRd, regRs);
+               for (i = 0; i < 5; i++) {
+                  mask[i] = newTemp(ty);
+                  shift[i] = 1 << i;
+               }
+               if(mode64) {
+                  assign(mask[0], mkU64(0x0000000055555555));
+                  assign(mask[1], mkU64(0x0000000033333333));
+                  assign(mask[2], mkU64(0x000000000F0F0F0F));
+                  assign(mask[3], mkU64(0x0000000000FF00FF));
+                  assign(mask[4], mkU64(0x000000000000FFFF));
+  
+                  for (i = 0; i < 5; i++) {
+                     nyu = newTemp(ty);
+                     assign(nyu,
+                            binop(Iop_Add64,
+                                  binop(Iop_And64,
+                                        mkexpr(old), mkexpr(mask[i])),
+                                  binop(Iop_And64,
+                                        binop(Iop_Shr64,
+                                              mkexpr(old), mkU8(shift[i])),
+                                        mkexpr(mask[i]))));
+                     old = nyu;
+                  }
+               } else {
+                  assign(mask[0], mkU32(0x55555555));
+                  assign(mask[1], mkU32(0x33333333));
+                  assign(mask[2], mkU32(0x0F0F0F0F));
+                  assign(mask[3], mkU32(0x00FF00FF));
+                  assign(mask[4], mkU32(0x0000FFFF));
+                  assign(old, getIReg(regRs));
+                  for (i = 0; i < 5; i++) {
+                     nyu = newTemp(ty);
+                     assign(nyu,
+                            binop(Iop_Add32,
+                                  binop(Iop_And32,
+                                        mkexpr(old), mkexpr(mask[i])),
+                                  binop(Iop_And32,
+                                        binop(Iop_Shr32,
+                                              mkexpr(old), mkU8(shift[i])),
+                                        mkexpr(mask[i]))));
+                     old = nyu;
+                  }
+               }
+               putIReg(regRd, mkexpr(nyu));
+               break;
+            }
+            /* Count Ones in a Doubleword - DPOP; Cavium OCTEON */
+            case 0x2d: {
+               int i, shift[6];
+               IRTemp mask[6];
+               IRTemp old = newTemp(ty);
+               IRTemp nyu = IRTemp_INVALID;
+               DIP("dpop r%d, r%d", regRd, regRs);
+               for (i = 0; i < 6; i++) {
+                  mask[i] = newTemp(ty);
+                  shift[i] = 1 << i;
+               }
+               vassert(mode64); /*Caution! Only for Mode 64*/
+               assign(mask[0], mkU64(0x5555555555555555ULL));
+               assign(mask[1], mkU64(0x3333333333333333ULL));
+               assign(mask[2], mkU64(0x0F0F0F0F0F0F0F0FULL));
+               assign(mask[3], mkU64(0x00FF00FF00FF00FFULL));
+               assign(mask[4], mkU64(0x0000FFFF0000FFFFULL));
+               assign(mask[5], mkU64(0x00000000FFFFFFFFULL));
+               assign(old, getIReg(regRs));
+               for (i = 0; i < 6; i++) {
+                  nyu = newTemp(Ity_I64);
+                  assign(nyu,
+                         binop(Iop_Add64,
+                               binop(Iop_And64,
+                                     mkexpr(old), mkexpr(mask[i])),
+                               binop(Iop_And64,
+                                     binop(Iop_Shr64,
+                                           mkexpr(old), mkU8(shift[i])),
+                                     mkexpr(mask[i]))));
+                  old = nyu;
+               }
+               putIReg(regRd, mkexpr(nyu));
+               break;
+            }
+
             case 0x32:  /* 5. CINS rd, rs, p, lenm1 */
                DIP("cins r%u, r%u, %d, %d\n", regRt, regRs, p, lenM1); 
                assign ( tmp  , binop(Iop_Shl64, mkexpr(tmpRs),
@@ -2291,7 +2618,7 @@ static Bool dis_instr_CVM ( UInt theInstr )
          }
          break;
       } /* opc1 0x1C ends here*/
-      case 0x1F:{
+      case 0x1F: {
          switch(opc2) {
             case 0x0A: {  // lx - Load indexed instructions
                switch (get_sa(theInstr)) {
@@ -14120,34 +14447,40 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *,
 
    case 0x1C:  /* Special2 */
       switch (function) {
-      /* Cavium Specific instructions */
-      case 0x03: case 0x32: case 0x33:  /* DMUL, CINS , CINS32 */
-      case 0x3A: case 0x3B: case 0x2B:  /* EXT,  EXT32, SNE    */
-      /* CVM Compare Instructions */
-      case 0x2A: case 0x2E: case 0x2F:  /* SEQ,  SEQI,  SNEI   */
-         if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
-            if (dis_instr_CVM(cins))
-               break;
-            goto decode_failure;
-         } else {
-            goto decode_failure;
-         }
+         /* Cavium Specific instructions */
+         case 0x03: case 0x32: case 0x33:  /* DMUL, CINS , CINS32 */
+         case 0x3A: case 0x3B: case 0x2B:  /* EXT,  EXT32, SNE    */
+         /* CVM Compare Instructions */
+         case 0x2A: case 0x2E: case 0x2F:  /* SEQ,  SEQI,  SNEI   */
+         /* CPU Load, Store, Memory, and Control Instructions */
+         case 0x18: case 0x19:             /* SAA, SAAD */
+         case 0x1F:                        /* LAA, LAAD, LAI, LAID */
+         case 0x28: case 0x2C: case 0x2D:  /* BADDU, POP, DPOP */
+            if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
+               if (dis_instr_CVM(cins))
+                  break;
+               goto decode_failure;
+            } else {
+               goto decode_failure;
+            }
          break;
-      case 0x02: {  /* MUL */
-         DIP("mul r%d, r%d, r%d", rd, rs, rt);
-         if (mode64) {
-            IRTemp tmpRs32 = newTemp(Ity_I32);
-            IRTemp tmpRt32 = newTemp(Ity_I32);
-            IRTemp tmpRes = newTemp(Ity_I32);
 
-            assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
-            assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
-            assign(tmpRes, binop(Iop_Mul32, mkexpr(tmpRs32), mkexpr(tmpRt32)));
-            putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpRes), True));
-         } else
-            putIReg(rd, binop(Iop_Mul32, getIReg(rs), getIReg(rt)));
-         break;
-      }
+         case 0x02: {  /* MUL */
+            DIP("mul r%d, r%d, r%d", rd, rs, rt);
+            if (mode64) {
+               IRTemp tmpRs32 = newTemp(Ity_I32);
+               IRTemp tmpRt32 = newTemp(Ity_I32);
+               IRTemp tmpRes = newTemp(Ity_I32);
+
+               assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
+               assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
+               assign(tmpRes, binop(Iop_Mul32,
+                                    mkexpr(tmpRs32), mkexpr(tmpRt32)));
+               putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpRes), True));
+            } else
+               putIReg(rd, binop(Iop_Mul32, getIReg(rs), getIReg(rt)));
+            break;
+         }
 
          case 0x00: {  /* MADD */
             if (mode64) {
index ca92f89f90fbd7f606ea943733153915ca19e5d8..1bf81b2f59e45c1aeb85b738e7f077823b7a9c9d 100644 (file)
@@ -1399,6 +1399,23 @@ MIPSInstr *MIPSInstr_LoadL(UChar sz, HReg dst, MIPSAMode * src, Bool mode64)
    return i;
 }
 
+MIPSInstr *MIPSInstr_Cas(UChar sz, HReg old, HReg addr,
+                         HReg expd, HReg data, Bool mode64)
+{
+   MIPSInstr *i    = LibVEX_Alloc(sizeof(MIPSInstr));
+   i->tag          = Min_Cas;
+   i->Min.Cas.sz   = sz;
+   i->Min.Cas.old  = old;
+   i->Min.Cas.addr = addr;
+   i->Min.Cas.expd = expd;
+   i->Min.Cas.data = data;
+   vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
+
+   if (sz == 8)
+      vassert(mode64);
+   return i;
+}
+
 MIPSInstr *MIPSInstr_StoreC(UChar sz, MIPSAMode * dst, HReg src, Bool mode64)
 {
    MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
@@ -1777,6 +1794,55 @@ void ppMIPSInstr(MIPSInstr * i, Bool mode64)
          ppMIPSAMode(i->Min.LoadL.src, mode64);
          return;
       }
+      case Min_Cas: {
+          Bool sz8  = toBool(i->Min.Cas.sz == 8);
+          /*
+           * ll(d)    old,  0(addr)
+           * bne      old,  expd, end
+           * nop
+           * (d)addiu old,  old,  1
+           * sc(d)    data, 0(addr)
+           * movn     old,  expd, data
+           * end:
+           */
+          // ll(d) old, 0(addr)
+         vex_printf("cas: ");
+
+         vex_printf("%s ", sz8 ? "lld" : "ll");
+         ppHRegMIPS(i->Min.Cas.old , mode64);
+         vex_printf(", 0(");
+         ppHRegMIPS(i->Min.Cas.addr , mode64);
+         vex_printf(")\n");
+
+         vex_printf("bne ");
+         ppHRegMIPS(i->Min.Cas.old , mode64);
+         vex_printf(", ");
+         ppHRegMIPS(i->Min.Cas.expd , mode64);
+         vex_printf(", end\n");
+
+         vex_printf("nop\n");
+
+         vex_printf("%s ", sz8 ? "daddiu" : "addiu");
+         ppHRegMIPS(i->Min.Cas.old , mode64);
+         vex_printf(", ");
+         ppHRegMIPS(i->Min.Cas.old , mode64);
+         vex_printf(", 1\n");
+
+         vex_printf("%s ", sz8 ? "scd" : "sc");
+         ppHRegMIPS(i->Min.Cas.data , mode64);
+         vex_printf(", 0(");
+         ppHRegMIPS(i->Min.Cas.addr , mode64);
+         vex_printf(")\n");
+
+         vex_printf("movn ");
+         ppHRegMIPS(i->Min.Cas.old , mode64);
+         vex_printf(", ");
+         ppHRegMIPS(i->Min.Cas.expd , mode64);
+         vex_printf(", ");
+         ppHRegMIPS(i->Min.Cas.data , mode64);
+         vex_printf("\nend:");
+         return;
+      }
       case Min_StoreC: {
          vex_printf("sc ");
          ppHRegMIPS(i->Min.StoreC.src, mode64);
@@ -2062,6 +2128,12 @@ void getRegUsage_MIPSInstr(HRegUsage * u, MIPSInstr * i, Bool mode64)
          addRegUsage_MIPSAMode(u, i->Min.LoadL.src);
          addHRegUse(u, HRmWrite, i->Min.LoadL.dst);
          return;
+      case Min_Cas:
+         addHRegUse(u, HRmWrite, i->Min.Cas.old);
+         addHRegUse(u, HRmRead, i->Min.Cas.addr);
+         addHRegUse(u, HRmRead, i->Min.Cas.expd);
+         addHRegUse(u, HRmModify, i->Min.Cas.data);
+         return;
       case Min_StoreC:
          addHRegUse(u, HRmWrite, i->Min.StoreC.src);
          addHRegUse(u, HRmRead, i->Min.StoreC.src);
@@ -2214,6 +2286,12 @@ void mapRegs_MIPSInstr(HRegRemap * m, MIPSInstr * i, Bool mode64)
          mapRegs_MIPSAMode(m, i->Min.LoadL.src);
          mapReg(m, &i->Min.LoadL.dst);
          return;
+      case Min_Cas:
+         mapReg(m, &i->Min.Cas.old);
+         mapReg(m, &i->Min.Cas.addr);
+         mapReg(m, &i->Min.Cas.expd);
+         mapReg(m, &i->Min.Cas.data);
+         return;
       case Min_StoreC:
          mapReg(m, &i->Min.StoreC.src);
          mapRegs_MIPSAMode(m, i->Min.StoreC.dst);
@@ -3459,8 +3537,8 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc,
          switch (i->Min.XAssisted.jk) {
             case Ijk_ClientReq:     trcval = VEX_TRC_JMP_CLIENTREQ;     break;
             case Ijk_Sys_syscall:   trcval = VEX_TRC_JMP_SYS_SYSCALL;   break;
-            /* case Ijk_Sys_int128: trcval = VEX_TRC_JMP_SYS_INT128;    break;
-               case Ijk_Yield:     trcval = VEX_TRC_JMP_YIELD;         break; */
+            /* case Ijk_Sys_int128: trcval = VEX_TRC_JMP_SYS_INT128;   break; */
+            case Ijk_Yield:         trcval = VEX_TRC_JMP_YIELD;       break;
             case Ijk_EmWarn:        trcval = VEX_TRC_JMP_EMWARN;        break;
             case Ijk_EmFail:        trcval = VEX_TRC_JMP_EMFAIL;        break;
             /* case Ijk_MapFail:   trcval = VEX_TRC_JMP_MAPFAIL;       break; */
@@ -3646,6 +3724,39 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc,
             p = mkFormI(p, 0x3C, r_dst, r_src, idx);
          goto done;
       }
+      case Min_Cas: {
+         if (i->Min.Cas.sz != 8 && i->Min.Cas.sz != 4)
+            goto bad;
+         UInt old  = iregNo(i->Min.Cas.old, mode64);
+         UInt addr = iregNo(i->Min.Cas.addr, mode64);
+         UInt expd = iregNo(i->Min.Cas.expd, mode64);
+         UInt data = iregNo(i->Min.Cas.data, mode64);
+         Bool sz8  = toBool(i->Min.Cas.sz == 8);
+
+         /*
+          * ll(d)    old,  0(addr)
+          * bne      old,  expd, end
+          * nop
+          * (d)addiu old,  old,  1
+          * sc(d)    data, 0(addr)
+          * movn     old,  expd, data
+          * end:
+          */
+         // ll(d) old, 0(addr)
+         p = mkFormI(p, sz8 ? 0x34 : 0x30, addr, old, 0);
+         // bne  old,  expd, end
+         p = mkFormI(p, 5, old, expd, 4);
+         // nop
+         p = mkFormR(p, 0, 0, 0, 0, 0, 0);
+         // (d)addiu old,  old,  1
+         p = mkFormI(p, sz8 ? 25 : 9, old, old, 1);
+         // sc(d)  data, 0(addr)
+         p = mkFormI(p, sz8 ? 0x3C : 0x38, addr, data, 0);
+         // movn old,  expd, data
+         p = mkFormR(p, 0, expd, data, old, 0, 0xb);
+
+         goto done;
+      }
       case Min_RdWrLR: {
          UInt reg = iregNo(i->Min.RdWrLR.gpr, mode64);
          Bool wrLR = i->Min.RdWrLR.wrLR;
index cc2b48fc64dbf7766f6105bacef56659b3d72f74..22881eea820d2f208059cff30edd737c5d2ae4e6 100644 (file)
@@ -325,6 +325,7 @@ typedef enum {
 
    Min_Load,       /* zero-extending load a 8|16|32 bit value from mem */
    Min_Store,      /* store a 8|16|32 bit value to mem */
+   Min_Cas,        /* compare and swap */
    Min_LoadL,      /* mips Load Linked Word - LL */
    Min_StoreC,     /* mips Store Conditional Word - SC */
 
@@ -519,6 +520,13 @@ typedef struct {
          HReg dst;
          MIPSAMode *src;
       } LoadL;
+      struct {
+         UChar sz;   /* 4|8 */
+         HReg  old;
+         HReg  addr;
+         HReg  expd;
+         HReg  data;
+      } Cas;
       struct {
          UChar sz;   /* 4|8 */
          MIPSAMode *dst;
@@ -649,6 +657,8 @@ extern MIPSInstr *MIPSInstr_LoadL(UChar sz, HReg dst, MIPSAMode * src,
                                   Bool mode64);
 extern MIPSInstr *MIPSInstr_StoreC(UChar sz, MIPSAMode * dst, HReg src,
                                    Bool mode64);
+extern MIPSInstr *MIPSInstr_Cas(UChar sz, HReg old, HReg addr,
+                                HReg expd, HReg data, Bool mode64);
 
 extern MIPSInstr *MIPSInstr_Call ( MIPSCondCode, Addr64, UInt, HReg, RetLoc );
 extern MIPSInstr *MIPSInstr_CallAlways ( MIPSCondCode, Addr64, UInt, RetLoc );
index 572edf446216c054e7f95a2afe8a5a8fbfec8c9d..233367d925f65ae678f2d45d5c20139f0a619d39 100644 (file)
@@ -971,7 +971,9 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e)
              || e->Iex.Binop.op == Iop_CmpLE32S
              || e->Iex.Binop.op == Iop_CmpLE64S
              || e->Iex.Binop.op == Iop_CmpLT64S
-             || e->Iex.Binop.op == Iop_CmpEQ64) {
+             || e->Iex.Binop.op == Iop_CmpEQ64
+             || e->Iex.Binop.op == Iop_CasCmpEQ32
+             || e->Iex.Binop.op == Iop_CasCmpEQ64) {
 
             Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
                          || e->Iex.Binop.op == Iop_CmpLE32S
@@ -986,6 +988,7 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e)
 
             switch (e->Iex.Binop.op) {
                case Iop_CmpEQ32:
+               case Iop_CasCmpEQ32:
                   cc = MIPScc_EQ;
                   size32 = True;
                   break;
@@ -1030,6 +1033,7 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e)
                   size32 = False;
                   break;
                case Iop_CmpEQ64:
+               case Iop_CasCmpEQ64:
                   cc = MIPScc_EQ;
                   size32 = False;
                   break;
@@ -2051,7 +2055,9 @@ static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e)
        || e->Iex.Binop.op == Iop_CmpLE32S
        || e->Iex.Binop.op == Iop_CmpLE64S
        || e->Iex.Binop.op == Iop_CmpLT64S
-       || e->Iex.Binop.op == Iop_CmpEQ64) {
+       || e->Iex.Binop.op == Iop_CmpEQ64
+       || e->Iex.Binop.op == Iop_CasCmpEQ32
+       || e->Iex.Binop.op == Iop_CasCmpEQ64) {
 
       Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
                    || e->Iex.Binop.op == Iop_CmpLE32S
@@ -2066,6 +2072,7 @@ static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e)
 
       switch (e->Iex.Binop.op) {
          case Iop_CmpEQ32:
+         case Iop_CasCmpEQ32:
             cc = MIPScc_EQ;
             size32 = True;
             break;
@@ -2102,6 +2109,7 @@ static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e)
             size32 = False;
             break;
          case Iop_CmpEQ64:
+         case Iop_CasCmpEQ64:
             cc = MIPScc_EQ;
             size32 = False;
             break;
@@ -3933,6 +3941,20 @@ static void iselStmt(ISelEnv * env, IRStmt * stmt)
          goto stmt_fail;
        /* NOTREACHED */}
 
+   case Ist_CAS:
+      if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
+         IRCAS *cas = stmt->Ist.CAS.details;
+         HReg old   = lookupIRTemp(env, cas->oldLo);
+         HReg addr  = iselWordExpr_R(env, cas->addr);
+         HReg expd  = iselWordExpr_R(env, cas->expdLo);
+         HReg data  = iselWordExpr_R(env, cas->dataLo);
+         if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I64) {
+            addInstr(env, MIPSInstr_Cas(8, old, addr, expd, data, mode64));
+         } else if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
+            addInstr(env, MIPSInstr_Cas(4, old, addr, expd, data, mode64));
+         }
+      }
+
    /* --------- INSTR MARK --------- */
    /* Doesn't generate any executable code ... */
    case Ist_IMark:
@@ -3997,6 +4019,7 @@ static void iselStmt(ISelEnv * env, IRStmt * stmt)
          case Ijk_NoDecode:
          case Ijk_NoRedir:
          case Ijk_SigBUS:
+         case Ijk_Yield:
          case Ijk_SigTRAP:
          case Ijk_SigFPE_IntDiv:
          case Ijk_SigFPE_IntOvf: