]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add infrastructural support (IR, VEX) to allow returns of 128-
authorJulian Seward <jseward@acm.org>
Thu, 8 Aug 2013 10:28:59 +0000 (10:28 +0000)
committerJulian Seward <jseward@acm.org>
Thu, 8 Aug 2013 10:28:59 +0000 (10:28 +0000)
and 256-bit values from dirty helper functions, in a way which is
independent of the target ABIs and of compilers generating
correct struct return code.

Is a prereq for bug #294285.

MIPS fixes: Petar Jovanovic, mips32r2@gmail.com
S390 fixes: Maran, maranp@linux.vnet.ibm.com

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

26 files changed:
VEX/priv/guest_amd64_toIR.c
VEX/priv/guest_mips_defs.h
VEX/priv/guest_mips_helpers.c
VEX/priv/guest_mips_toIR.c
VEX/priv/guest_ppc_toIR.c
VEX/priv/guest_s390_toIR.c
VEX/priv/guest_x86_toIR.c
VEX/priv/host_amd64_defs.c
VEX/priv/host_amd64_isel.c
VEX/priv/host_arm_defs.c
VEX/priv/host_arm_isel.c
VEX/priv/host_generic_regs.c
VEX/priv/host_generic_regs.h
VEX/priv/host_mips_defs.c
VEX/priv/host_mips_isel.c
VEX/priv/host_ppc_defs.c
VEX/priv/host_ppc_isel.c
VEX/priv/host_s390_defs.c
VEX/priv/host_s390_defs.h
VEX/priv/host_s390_isel.c
VEX/priv/host_x86_defs.c
VEX/priv/host_x86_isel.c
VEX/priv/ir_defs.c
VEX/priv/ir_opt.c
VEX/priv/main_main.c
VEX/pub/libvex_ir.h

index dae12db25ee91c1e50e40d0348cc0ff73fa72842..cea4c009ae841e4e47444baa6acfa4fdfef74b59 100644 (file)
@@ -5356,10 +5356,9 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                                  0/*regparms*/, 
                                  "amd64g_dirtyhelper_FLDENV", 
                                  &amd64g_dirtyhelper_FLDENV,
-                                 mkIRExprVec_1( mkexpr(addr) )
+                                 mkIRExprVec_2( IRExprP__BBPTR, mkexpr(addr) )
                               );
-               d->needsBBP = True;
-               d->tmp      = w64;
+               d->tmp       = w64;
                /* declare we're reading memory */
                d->mFx   = Ifx_Read;
                d->mAddr = mkexpr(addr);
@@ -5454,9 +5453,8 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                                0/*regparms*/, 
                                "amd64g_dirtyhelper_FSTENV", 
                                &amd64g_dirtyhelper_FSTENV,
-                               mkIRExprVec_1( mkexpr(addr) )
+                               mkIRExprVec_2( IRExprP__BBPTR, mkexpr(addr) )
                             );
-               d->needsBBP = True;
                /* declare we're writing memory */
                d->mFx   = Ifx_Write;
                d->mAddr = mkexpr(addr);
@@ -6108,9 +6106,8 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                                 0/*regparms*/, 
                                 "amd64g_dirtyhelper_FINIT", 
                                 &amd64g_dirtyhelper_FINIT,
-                                mkIRExprVec_0()
+                                mkIRExprVec_1( IRExprP__BBPTR )
                              );
-               d->needsBBP = True;
 
                /* declare we're writing guest state */
                d->nFxState = 5;
@@ -6324,13 +6321,12 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                          0/*regparms*/, 
                          "amd64g_dirtyhelper_FRSTOR",
                          &amd64g_dirtyhelper_FRSTOR,
-                         mkIRExprVec_1( mkexpr(addr) )
+                         mkIRExprVec_2( IRExprP__BBPTR, mkexpr(addr) )
                       );
                   d->mSize = 108;
                }
 
-               d->needsBBP = True;
-               d->tmp      = w64;
+               d->tmp    = w64;
                /* declare we're reading memory */
                d->mFx   = Ifx_Read;
                d->mAddr = mkexpr(addr);
@@ -6389,7 +6385,8 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                IRDirty *d;
                if ( have66(pfx) ) {
                  /* Uses dirty helper: 
-                    void amd64g_dirtyhelper_FNSAVES ( VexGuestX86State*, HWord ) */
+                    void amd64g_dirtyhelper_FNSAVES ( VexGuestAMD64State*,
+                                                      HWord ) */
                   d = unsafeIRDirty_0_N ( 
                          0/*regparms*/, 
                          "amd64g_dirtyhelper_FNSAVES", 
@@ -6399,16 +6396,17 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                   d->mSize = 94;
                } else {
                  /* Uses dirty helper: 
-                    void amd64g_dirtyhelper_FNSAVE ( VexGuestX86State*, HWord ) */
+                    void amd64g_dirtyhelper_FNSAVE ( VexGuestAMD64State*,
+                                                     HWord ) */
                   d = unsafeIRDirty_0_N ( 
                          0/*regparms*/, 
                          "amd64g_dirtyhelper_FNSAVE",
                          &amd64g_dirtyhelper_FNSAVE,
-                         mkIRExprVec_1( mkexpr(addr) )
-                         );
+                         mkIRExprVec_2( IRExprP__BBPTR, mkexpr(addr) )
+                      );
                   d->mSize = 108;
                }
-               d->needsBBP = True;
+
                /* declare we're writing memory */
                d->mFx   = Ifx_Write;
                d->mAddr = mkexpr(addr);
@@ -13294,9 +13292,8 @@ Long dis_ESC_0F__SSE2 ( Bool* decode_OK,
                 0/*regparms*/, 
                 "amd64g_dirtyhelper_FXSAVE", 
                 &amd64g_dirtyhelper_FXSAVE,
-                mkIRExprVec_1( mkexpr(addr) )
+                mkIRExprVec_2( IRExprP__BBPTR, mkexpr(addr) )
              );
-         d->needsBBP = True;
 
          /* declare we're writing memory */
          d->mFx   = Ifx_Write;
@@ -13373,9 +13370,8 @@ Long dis_ESC_0F__SSE2 ( Bool* decode_OK,
                 0/*regparms*/, 
                 "amd64g_dirtyhelper_FXRSTOR", 
                 &amd64g_dirtyhelper_FXRSTOR,
-                mkIRExprVec_1( mkexpr(addr) )
+                mkIRExprVec_2( IRExprP__BBPTR, mkexpr(addr) )
              );
-         d->needsBBP = True;
 
          /* declare we're reading memory */
          d->mFx   = Ifx_Read;
@@ -16921,14 +16917,12 @@ static Long dis_AESx ( VexAbiInfo* vbi, Prefix pfx,
    IRExpr*  gstOffLe     = mkU64(gstOffL);
    IRExpr*  gstOffRe     = mkU64(gstOffR);
    IRExpr** args
-      = mkIRExprVec_4( opc4, gstOffDe, gstOffLe, gstOffRe );
+      = mkIRExprVec_5( IRExprP__BBPTR, opc4, gstOffDe, gstOffLe, gstOffRe );
 
    IRDirty* d    = unsafeIRDirty_0_N( 0/*regparms*/, nm, fn, args );
-   /* It's not really a dirty call, but we can't use the clean
-      helper mechanism here for the very lame reason that we can't
-      pass 2 x V128s by value to a helper, nor get one back.  Hence
-      this roundabout scheme. */
-   d->needsBBP = True;
+   /* It's not really a dirty call, but we can't use the clean helper
+      mechanism here for the very lame reason that we can't pass 2 x
+      V128s by value to a helper.  Hence this roundabout scheme. */
    d->nFxState = 2;
    vex_bzero(&d->fxState, sizeof(d->fxState));
    /* AES{ENC,ENCLAST,DEC,DECLAST} read both registers, and writes
@@ -17013,14 +17007,12 @@ static Long dis_AESKEYGENASSIST ( VexAbiInfo* vbi, Prefix pfx,
    IRExpr*  gstOffLe     = mkU64(gstOffL);
    IRExpr*  gstOffRe     = mkU64(gstOffR);
    IRExpr** args
-      = mkIRExprVec_3( imme, gstOffLe, gstOffRe );
+      = mkIRExprVec_4( IRExprP__BBPTR, imme, gstOffLe, gstOffRe );
 
    IRDirty* d    = unsafeIRDirty_0_N( 0/*regparms*/, nm, fn, args );
-   /* It's not really a dirty call, but we can't use the clean
-      helper mechanism here for the very lame reason that we can't
-      pass 2 x V128s by value to a helper, nor get one back.  Hence
-      this roundabout scheme. */
-   d->needsBBP = True;
+   /* It's not really a dirty call, but we can't use the clean helper
+      mechanism here for the very lame reason that we can't pass 2 x
+      V128s by value to a helper.  Hence this roundabout scheme. */
    d->nFxState = 2;
    vex_bzero(&d->fxState, sizeof(d->fxState));
    d->fxState[0].fx     = Ifx_Read;
@@ -17944,15 +17936,14 @@ static Long dis_PCMPxSTRx ( VexAbiInfo* vbi, Prefix pfx,
    IRExpr*  edxIN        = isISTRx ? mkU64(0) : getIRegRDX(8);
    IRExpr*  eaxIN        = isISTRx ? mkU64(0) : getIRegRAX(8);
    IRExpr** args
-      = mkIRExprVec_5( opc4_and_imm, gstOffLe, gstOffRe, edxIN, eaxIN );
+      = mkIRExprVec_6( IRExprP__BBPTR,
+                       opc4_and_imm, gstOffLe, gstOffRe, edxIN, eaxIN );
 
    IRTemp   resT = newTemp(Ity_I64);
    IRDirty* d    = unsafeIRDirty_1_N( resT, 0/*regparms*/, nm, fn, args );
    /* It's not really a dirty call, but we can't use the clean helper
       mechanism here for the very lame reason that we can't pass 2 x
-      V128s by value to a helper, nor get one back.  Hence this
-      roundabout scheme. */
-   d->needsBBP = True;
+      V128s by value to a helper.  Hence this roundabout scheme. */
    d->nFxState = 2;
    vex_bzero(&d->fxState, sizeof(d->fxState));
    d->fxState[0].fx     = Ifx_Read;
@@ -20720,9 +20711,8 @@ Long dis_ESC_0F (
          void*        fAddr = &amd64g_dirtyhelper_RDTSCP;
          IRDirty* d
             = unsafeIRDirty_0_N ( 0/*regparms*/, 
-                                  fName, fAddr, mkIRExprVec_0() );
+                                  fName, fAddr, mkIRExprVec_1(IRExprP__BBPTR) );
          /* declare guest state effects */
-         d->needsBBP = True;
          d->nFxState = 3;
          vex_bzero(&d->fxState, sizeof(d->fxState));
          d->fxState[0].fx     = Ifx_Write;
@@ -20969,9 +20959,8 @@ Long dis_ESC_0F (
 
       vassert(fName); vassert(fAddr);
       d = unsafeIRDirty_0_N ( 0/*regparms*/, 
-                              fName, fAddr, mkIRExprVec_0() );
+                              fName, fAddr, mkIRExprVec_1(IRExprP__BBPTR) );
       /* declare guest state effects */
-      d->needsBBP = True;
       d->nFxState = 4;
       vex_bzero(&d->fxState, sizeof(d->fxState));
       d->fxState[0].fx     = Ifx_Modify;
index 45a91a76d2c31ad85b20ca397b5e488c793d62dc..2ab3868b764f908909deff990321b416403678e6 100644 (file)
@@ -83,7 +83,6 @@ extern UInt mips32_dirtyhelper_mfc0 ( UInt rd, UInt sel );
 
 extern ULong mips64_dirtyhelper_dmfc0 ( UInt rd, UInt sel );
 
-extern void mips32_dirtyhelper_sync ( UInt sync );
 
 #if defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev >= 2))
 extern ULong mips64_dirtyhelper_rdhwr ( ULong rt, ULong rd );
index 80ee906e9441af4ed5c9eb0890d8815e11b58bf7..1e2c20b3a87b4b9aa8a032618acacd43f738a330 100644 (file)
@@ -1075,16 +1075,6 @@ ULong mips64_dirtyhelper_dmfc0 ( UInt rd, UInt sel )
 #define ASM_VOLATILE_CASE(rd, sel) \
    case rd: asm volatile ("dmfc0 %0, $" #rd ", "#sel"\n\t" :"=r" (x) ); break;
 
-#define ASM_VOLATILE_SYNC(stype) \
-        asm volatile ("sync \n\t");
-
-void mips32_dirtyhelper_sync(UInt stype)
-{
-#if defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev >= 2))
-   ASM_VOLATILE_SYNC(0);
-#endif
-}
-
 #if defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev >= 2))
 ULong mips64_dirtyhelper_rdhwr ( ULong rt, ULong rd )
 {
index b31dbcaa39df25018acdecd7de09777abae4b521..c3709e37bf9e144fa79553782851495082f5c38b 100644 (file)
@@ -12488,7 +12488,7 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *,
       if (rs == 0) {  /* MFC0 */
          DIP("mfc0 r%d, r%d, %d", rt, rd, sel);
          IRTemp   val  = newTemp(Ity_I32);
-         IRExpr** args = mkIRExprVec_2 (mkU32(rd), mkU32(sel));
+         IRExpr** args = mkIRExprVec_3 (IRExprP__BBPTR, mkU32(rd), mkU32(sel));
          IRDirty *d = unsafeIRDirty_1_N(val,
                                         0,
                                         "mips32_dirtyhelper_mfc0",
@@ -12500,7 +12500,7 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *,
          /* Doubleword Move from Coprocessor 0 - DMFC0; MIPS64 */
          DIP("dmfc0 r%d, r%d, %d", rt, rd, sel);
          IRTemp   val  = newTemp(Ity_I64);
-         IRExpr** args = mkIRExprVec_2 (mkU64(rd), mkU64(sel));
+         IRExpr** args = mkIRExprVec_3 (IRExprP__BBPTR, mkU64(rd), mkU64(sel));
          IRDirty *d = unsafeIRDirty_1_N(val,
                                         0,
                                         "mips64_dirtyhelper_dmfc0",
@@ -14166,7 +14166,8 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *,
 #if defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev >= 2))
             } else if (rd == 1) {
                IRTemp   val  = newTemp(Ity_I64);
-               IRExpr** args = mkIRExprVec_2 (mkU64(rt), mkU64(rd));
+               IRExpr** args = mkIRExprVec_3 (IRExprP__BBPTR,
+                                              mkU64(rt), mkU64(rd));
                IRDirty *d = unsafeIRDirty_1_N(val,
                                               0,
                                               "mips64_dirtyhelper_rdhwr",
@@ -15410,21 +15411,10 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *,
             break;
          goto decode_failure;
 
-      case 0x0F:  /* SYNC */
+      case 0x0F:  /* SYNC */
          DIP("sync 0x%x", sel);
-         lsb = get_lsb(cins);
-         IRDirty *d = unsafeIRDirty_0_N(0,
-                                        "mips32_dirtyhelper_sync",
-                                        &mips32_dirtyhelper_sync,
-                                        mkIRExprVec_1
-                                        (mkU32(lsb)));
-
-         d->needsBBP = False;
-         d->nFxState = 0;
-
-         stmt(IRStmt_Dirty(d));
+         /* Just ignore it. */
          break;
-      }
 
       case 0x2C: {  /* Doubleword Add - DADD; MIPS64 */
          DIP("dadd r%d, r%d, r%d", rd, rs, rt);
index fd9ac5b84fb10f090718c661520f6474e92abc38..e8301dbee09225c87928291f86f9dbbc8ffe98c6 100644 (file)
@@ -14377,7 +14377,8 @@ static Bool dis_av_load ( VexAbiInfo* vbi, UInt theInstr )
    case 0x006: { // lvsl (Load Vector for Shift Left, AV p123)
       IRDirty* d;
       UInt vD_off = vectorGuestRegOffset(vD_addr);
-      IRExpr** args = mkIRExprVec_3(
+      IRExpr** args = mkIRExprVec_4(
+                         IRExprP__BBPTR,
                          mkU32(vD_off), 
                          binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
                                           mkU32(0xF)),
@@ -14397,7 +14398,6 @@ static Bool dis_av_load ( VexAbiInfo* vbi, UInt theInstr )
       }
       DIP("lvsl v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
       /* declare guest state effects */
-      d->needsBBP = True;
       d->nFxState = 1;
       vex_bzero(&d->fxState, sizeof(d->fxState));
       d->fxState[0].fx     = Ifx_Write;
@@ -14411,7 +14411,8 @@ static Bool dis_av_load ( VexAbiInfo* vbi, UInt theInstr )
    case 0x026: { // lvsr (Load Vector for Shift Right, AV p125)
       IRDirty* d;
       UInt vD_off = vectorGuestRegOffset(vD_addr);
-      IRExpr** args = mkIRExprVec_3(
+      IRExpr** args = mkIRExprVec_4(
+                         IRExprP__BBPTR,
                          mkU32(vD_off), 
                          binop(Iop_And32, mkNarrowTo32(ty, mkexpr(EA)),
                                           mkU32(0xF)),
@@ -14431,7 +14432,6 @@ static Bool dis_av_load ( VexAbiInfo* vbi, UInt theInstr )
       }
       DIP("lvsr v%d,r%u,r%u\n", vD_addr, rA_addr, rB_addr);
       /* declare guest state effects */
-      d->needsBBP = True;
       d->nFxState = 1;
       vex_bzero(&d->fxState, sizeof(d->fxState));
       d->fxState[0].fx     = Ifx_Write;
index 2f715978a8a8841e3646de9a22c900537203fdaf..6ed1897982e7a211fbae9b6fc6620d402387c1df 100644 (file)
@@ -12874,11 +12874,10 @@ s390_irgen_STFLE(IRTemp op2addr)
    IRDirty *d;
    IRTemp cc = newTemp(Ity_I64);
 
+   /* IRExprP__BBPTR => Need to pass pointer to guest state to helper */
    d = unsafeIRDirty_1_N(cc, 0, "s390x_dirtyhelper_STFLE",
                          &s390x_dirtyhelper_STFLE,
-                         mkIRExprVec_1(mkexpr(op2addr)));
-
-   d->needsBBP = 1;  /* Need to pass pointer to guest state to helper */
+                         mkIRExprVec_2(IRExprP__BBPTR, mkexpr(op2addr)));
 
    d->nFxState = 1;
    vex_bzero(&d->fxState, sizeof(d->fxState));
index e9b96fcaf1eb9fac51b2f8733a83146d09afd0aa..11e0423cf0a1cdbeb0c2a01b518fa72ccf315d04 100644 (file)
@@ -3953,10 +3953,9 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
                                 0/*regparms*/, 
                                 "x86g_dirtyhelper_FLDENV", 
                                 &x86g_dirtyhelper_FLDENV,
-                                mkIRExprVec_1( mkexpr(addr) )
+                                mkIRExprVec_2( IRExprP__BBPTR, mkexpr(addr) )
                              );
-               d->needsBBP = True;
-               d->tmp      = ew;
+               d->tmp   = ew;
                /* declare we're reading memory */
                d->mFx   = Ifx_Read;
                d->mAddr = mkexpr(addr);
@@ -4050,9 +4049,8 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
                                0/*regparms*/, 
                                "x86g_dirtyhelper_FSTENV", 
                                &x86g_dirtyhelper_FSTENV,
-                               mkIRExprVec_1( mkexpr(addr) )
+                               mkIRExprVec_2( IRExprP__BBPTR, mkexpr(addr) )
                             );
-               d->needsBBP = True;
                /* declare we're writing memory */
                d->mFx   = Ifx_Write;
                d->mAddr = mkexpr(addr);
@@ -4736,9 +4734,8 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
                                 0/*regparms*/, 
                                 "x86g_dirtyhelper_FINIT", 
                                 &x86g_dirtyhelper_FINIT,
-                                mkIRExprVec_0()
+                                mkIRExprVec_1(IRExprP__BBPTR)
                              );
-               d->needsBBP = True;
 
                /* declare we're writing guest state */
                d->nFxState = 5;
@@ -4936,10 +4933,9 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
                                 0/*regparms*/, 
                                 "x86g_dirtyhelper_FRSTOR", 
                                 &x86g_dirtyhelper_FRSTOR,
-                                mkIRExprVec_1( mkexpr(addr) )
+                                mkIRExprVec_2( IRExprP__BBPTR, mkexpr(addr) )
                              );
-               d->needsBBP = True;
-               d->tmp      = ew;
+               d->tmp   = ew;
                /* declare we're reading memory */
                d->mFx   = Ifx_Read;
                d->mAddr = mkexpr(addr);
@@ -4996,9 +4992,8 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
                                0/*regparms*/, 
                                "x86g_dirtyhelper_FSAVE", 
                                &x86g_dirtyhelper_FSAVE,
-                               mkIRExprVec_1( mkexpr(addr) )
+                               mkIRExprVec_2( IRExprP__BBPTR, mkexpr(addr) )
                             );
-               d->needsBBP = True;
                /* declare we're writing memory */
                d->mFx   = Ifx_Write;
                d->mAddr = mkexpr(addr);
@@ -8192,9 +8187,8 @@ DisResult disInstr_X86_WRK (
              0/*regparms*/, 
              "x86g_dirtyhelper_FXSAVE", 
              &x86g_dirtyhelper_FXSAVE,
-             mkIRExprVec_1( mkexpr(addr) )
+             mkIRExprVec_2( IRExprP__BBPTR, mkexpr(addr) )
           );
-      d->needsBBP = True;
 
       /* declare we're writing memory */
       d->mFx   = Ifx_Write;
@@ -8267,9 +8261,8 @@ DisResult disInstr_X86_WRK (
              0/*regparms*/, 
              "x86g_dirtyhelper_FXRSTOR", 
              &x86g_dirtyhelper_FXRSTOR,
-             mkIRExprVec_1( mkexpr(addr) )
+             mkIRExprVec_2( IRExprP__BBPTR, mkexpr(addr) )
           );
-      d->needsBBP = True;
 
       /* declare we're reading memory */
       d->mFx   = Ifx_Read;
@@ -14689,9 +14682,8 @@ DisResult disInstr_X86_WRK (
 
          vassert(fName); vassert(fAddr);
          d = unsafeIRDirty_0_N ( 0/*regparms*/, 
-                                 fName, fAddr, mkIRExprVec_0() );
+                                 fName, fAddr, mkIRExprVec_1(IRExprP__BBPTR) );
          /* declare guest state effects */
-         d->needsBBP = True;
          d->nFxState = 4;
          vex_bzero(&d->fxState, sizeof(d->fxState));
          d->fxState[0].fx     = Ifx_Modify;
index e217cfef1f1ea77a04e0bc51c7483b1a45d926bd..99bad1f2f6bc721104dbbd1247a6f7212167071c 100644 (file)
@@ -702,7 +702,7 @@ AMD64Instr* AMD64Instr_Call ( AMD64CondCode cond, Addr64 target, Int regparms,
    i->Ain.Call.regparms = regparms;
    i->Ain.Call.rloc     = rloc;
    vassert(regparms >= 0 && regparms <= 6);
-   vassert(rloc != RetLocINVALID);
+   vassert(is_sane_RetLoc(rloc));
    return i;
 }
 
@@ -2671,7 +2671,8 @@ Int emit_AMD64Instr ( /*MB_MOD*/Bool* is_profInc,
       }
 
    case Ain_Call: {
-      if (i->Ain.Call.cond != Acc_ALWAYS && i->Ain.Call.rloc != RetLocNone) {
+      if (i->Ain.Call.cond != Acc_ALWAYS
+          && i->Ain.Call.rloc.pri != RLPri_None) {
          /* The call might not happen (it isn't unconditional) and it
             returns a result.  In this case we will need to generate a
             control flow diamond to put 0x555..555 in the return
index 9f2aa64fa277b02321f269955bc5e76aa57714e8..2ea772187870e3ee6835b2c23f3a6a9973dcf50e 100644 (file)
@@ -366,6 +366,15 @@ static AMD64Instr* iselIntExpr_single_instruction ( ISelEnv* env,
                                                     HReg     dst,
                                                     IRExpr*  e )
 {
+   /* Per comments in doHelperCall below, appearance of
+      IRExprP__VECRET implies ill-formed IR. */
+   vassert(e != IRExprP__VECRET);
+
+   /* In this case we give out a copy of the BaseBlock pointer. */
+   if (UNLIKELY(e == IRExprP__BBPTR)) {
+      return mk_iMOVsd_RR( hregAMD64_RBP(), dst );
+   }
+
    vassert(typeOfIRExpr(env->type_env, e) == Ity_I64);
 
    if (e->tag == Iex_Const) {
@@ -409,26 +418,36 @@ static AMD64Instr* iselIntExpr_single_instruction ( ISelEnv* env,
 }
 
 
-/* Do a complete function call.  guard is a Ity_Bit expression
+/* Do a complete function call.  |guard| is a Ity_Bit expression
    indicating whether or not the call happens.  If guard==NULL, the
-   call is unconditional. */
+   call is unconditional.  |retloc| is set to indicate where the
+   return value is after the call.  The caller (of this fn) must
+   generate code to add |stackAdjustAfterCall| to the stack pointer
+   after the call is done. */
 
 static
-void doHelperCall ( ISelEnv* env, 
-                    Bool passBBP, 
-                    IRExpr* guard, IRCallee* cee, IRExpr** args,
-                    RetLoc rloc )
+void doHelperCall ( /*OUT*/UInt*   stackAdjustAfterCall,
+                    /*OUT*/RetLoc* retloc,
+                    ISelEnv* env,
+                    IRExpr* guard,
+                    IRCallee* cee, IRType retTy, IRExpr** args )
 {
    AMD64CondCode cc;
    HReg          argregs[6];
    HReg          tmpregs[6];
    AMD64Instr*   fastinstrs[6];
-   Int           n_args, i, argreg;
+   UInt          n_args, i;
 
-   /* Marshal args for a call and do the call.
+   /* Set default returns.  We'll update them later if needed. */
+   *stackAdjustAfterCall = 0;
+   *retloc               = mk_RetLoc_INVALID();
 
-      If passBBP is True, %rbp (the baseblock pointer) is to be passed
-      as the first arg.
+   /* These are used for cross-checking that IR-level constraints on
+      the use of IRExprP__VECRET and IRExprP__BBPTR are observed. */
+   UInt nVECRETs = 0;
+   UInt nBBPTRs  = 0;
+
+   /* Marshal args for a call and do the call.
 
       This function only deals with a tiny set of possibilities, which
       cover all helpers in practice.  The restrictions are that only
@@ -436,6 +455,17 @@ void doHelperCall ( ISelEnv* env,
       bits in total can be passed.  In fact the only supported arg
       type is I64.
 
+      The return type can be I{64,32,16,8} or V{128,256}.  In the
+      latter two cases, it is expected that |args| will contain the
+      special value IRExprP__VECRET, in which case this routine
+      generates code to allocate space on the stack for the vector
+      return value.  Since we are not passing any scalars on the
+      stack, it is enough to preallocate the return space before
+      marshalling any arguments, in this case.
+
+      |args| may also contain IRExprP__BBPTR, in which case the
+      value in %rbp is passed as the corresponding argument.
+
       Generating code which is both efficient and correct when
       parameters are to be passed in registers is difficult, for the
       reasons elaborated in detail in comments attached to
@@ -461,7 +491,10 @@ void doHelperCall ( ISelEnv* env,
       fast scheme, else use the slow scheme.  Note also that only
       unconditional calls may use the fast scheme, since having to
       compute a condition expression could itself trash real
-      registers.
+      registers.  Note that for simplicity, in the case where
+      IRExprP__VECRET is present, we use the slow scheme.  This is
+      motivated by the desire to avoid any possible complexity
+      w.r.t. nested calls.
 
       Note this requires being able to examine an expression and
       determine whether or not evaluation of it might use a fixed
@@ -474,12 +507,11 @@ void doHelperCall ( ISelEnv* env,
    /* Note that the cee->regparms field is meaningless on AMD64 host
       (since there is only one calling convention) and so we always
       ignore it. */
-
    n_args = 0;
    for (i = 0; args[i]; i++)
       n_args++;
 
-   if (6 < n_args + (passBBP ? 1 : 0))
+   if (n_args > 6)
       vpanic("doHelperCall(AMD64): cannot currently handle > 6 args");
 
    argregs[0] = hregAMD64_RDI();
@@ -499,6 +531,12 @@ void doHelperCall ( ISelEnv* env,
       assume the fast scheme, and select slow if any contraindications
       (wow) appear. */
 
+   /* We'll need space on the stack for the return value.  Avoid
+      possible complications with nested calls by using the slow
+      scheme. */
+   if (retTy == Ity_V128 || retTy == Ity_V256)
+      goto slowscheme;
+
    if (guard) {
       if (guard->tag == Iex_Const 
           && guard->Iex.Const.con->tag == Ico_U1
@@ -517,26 +555,28 @@ void doHelperCall ( ISelEnv* env,
       in a buffer and emit that if we're successful. */
 
    /* FAST SCHEME */
-   argreg = 0;
-   if (passBBP) {
-      fastinstrs[argreg] = mk_iMOVsd_RR( hregAMD64_RBP(), argregs[argreg]);
-      argreg++;
-   }
-
+   /* In this loop, we process args that can be computed into the
+      destination (real) register with a single instruction, without
+      using any fixed regs.  That also includes IRExprP__BBPTR, but
+      not IRExprP__VECRET.  Indeed, if the IR is well-formed, we can
+      never see IRExprP__VECRET at this point, since the return-type
+      check above should ensure all those cases use the slow scheme
+      instead. */
+   vassert(n_args >= 0 && n_args <= 6);
    for (i = 0; i < n_args; i++) {
-      vassert(argreg < 6);
-      vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
-      fastinstrs[argreg] 
-         = iselIntExpr_single_instruction( env, argregs[argreg], args[i] );
-      if (fastinstrs[argreg] == NULL)
+      IRExpr* arg = args[i];
+      if (LIKELY(!is_IRExprP__VECRET_or_BBPTR(arg))) {
+         vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
+      }
+      fastinstrs[i] 
+         = iselIntExpr_single_instruction( env, argregs[i], args[i] );
+      if (fastinstrs[i] == NULL)
          goto slowscheme;
-      argreg++;
    }
 
    /* Looks like we're in luck.  Emit the accumulated instructions and
       move on to doing the call itself. */
-   vassert(argreg <= 6);
-   for (i = 0; i < argreg; i++)
+   for (i = 0; i < n_args; i++)
       addInstr(env, fastinstrs[i]);
 
    /* Fast scheme only applies for unconditional calls.  Hence: */
@@ -547,26 +587,47 @@ void doHelperCall ( ISelEnv* env,
 
    /* SLOW SCHEME; move via temporaries */
   slowscheme:
+   {}
 #  if 0 /* debug only */
    if (n_args > 0) {for (i = 0; args[i]; i++) {
    ppIRExpr(args[i]); vex_printf(" "); }
    vex_printf("\n");}
 #  endif
-   argreg = 0;
-
-   if (passBBP) {
-      /* This is pretty stupid; better to move directly to rdi
-         after the rest of the args are done. */
-      tmpregs[argreg] = newVRegI(env);
-      addInstr(env, mk_iMOVsd_RR( hregAMD64_RBP(), tmpregs[argreg]));
-      argreg++;
+
+   /* If we have a vector return type, allocate a place for it on the
+      stack and record its address. */
+   HReg r_vecRetAddr = INVALID_HREG;
+   if (retTy == Ity_V128) {
+      r_vecRetAddr = newVRegI(env);
+      sub_from_rsp(env, 16);
+      addInstr(env, mk_iMOVsd_RR( hregAMD64_RSP(), r_vecRetAddr ));
+   }
+   else if (retTy == Ity_V256) {
+      vassert(0); //ATC
+      r_vecRetAddr = newVRegI(env);
+      sub_from_rsp(env, 32);
+      addInstr(env, mk_iMOVsd_RR( hregAMD64_RSP(), r_vecRetAddr ));
    }
 
+   vassert(n_args >= 0 && n_args <= 6);
    for (i = 0; i < n_args; i++) {
-      vassert(argreg < 6);
-      vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
-      tmpregs[argreg] = iselIntExpr_R(env, args[i]);
-      argreg++;
+      IRExpr* arg = args[i];
+      if (UNLIKELY(arg == IRExprP__BBPTR)) {
+         tmpregs[i] = newVRegI(env);
+         addInstr(env, mk_iMOVsd_RR( hregAMD64_RBP(), tmpregs[i]));
+         nBBPTRs++;
+      }
+      else if (UNLIKELY(arg == IRExprP__VECRET)) {
+         /* We stashed the address of the return slot earlier, so just
+            retrieve it now. */
+         vassert(!hregIsInvalid(r_vecRetAddr));
+         tmpregs[i] = r_vecRetAddr;
+         nVECRETs++;
+      }
+      else {
+         vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
+         tmpregs[i] = iselIntExpr_R(env, args[i]);
+      }
    }
 
    /* Now we can compute the condition.  We can't do it earlier
@@ -585,21 +646,54 @@ void doHelperCall ( ISelEnv* env,
    }
 
    /* Move the args to their final destinations. */
-   for (i = 0; i < argreg; i++) {
+   for (i = 0; i < n_args; i++) {
       /* None of these insns, including any spill code that might
          be generated, may alter the condition codes. */
       addInstr( env, mk_iMOVsd_RR( tmpregs[i], argregs[i] ) );
    }
 
 
-   /* Finally, the call itself. */
+   /* Do final checks, set the return values, and generate the call
+      instruction proper. */
   handle_call:
-   addInstr(env, AMD64Instr_Call( 
-                    cc, 
-                    Ptr_to_ULong(cee->addr), 
-                    n_args + (passBBP ? 1 : 0), rloc
-                 )
-   );
+
+   if (retTy == Ity_V128 || retTy == Ity_V256) {
+      vassert(nVECRETs == 1);
+   } else {
+      vassert(nVECRETs == 0);
+   }
+
+   vassert(nBBPTRs == 0 || nBBPTRs == 1);
+
+   vassert(*stackAdjustAfterCall == 0);
+   vassert(is_RetLoc_INVALID(*retloc));
+   switch (retTy) {
+         case Ity_INVALID:
+            /* Function doesn't return a value. */
+            *retloc = mk_RetLoc_simple(RLPri_None);
+            break;
+         case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
+            *retloc = mk_RetLoc_simple(RLPri_Int);
+            break;
+         case Ity_V128:
+            *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 0);
+            *stackAdjustAfterCall = 16;
+            break;
+         case Ity_V256:
+            vassert(0); // ATC
+            *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 0);
+            *stackAdjustAfterCall = 32;
+            break;
+         default:
+            /* IR can denote other possible return types, but we don't
+               handle those here. */
+           vassert(0);
+   }
+
+   /* Finally, generate the call itself.  This needs the *retloc value
+      set in the switch above, which is why it's at the end. */
+   addInstr(env,
+            AMD64Instr_Call(cc, Ptr_to_ULong(cee->addr), n_args, *retloc));
 }
 
 
@@ -1136,7 +1230,8 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
             addInstr(env, AMD64Instr_MovxLQ(False, argR, argR));
          addInstr(env, mk_iMOVsd_RR(argL, hregAMD64_RDI()) );
          addInstr(env, mk_iMOVsd_RR(argR, hregAMD64_RSI()) );
-         addInstr(env, AMD64Instr_Call( Acc_ALWAYS, (ULong)fn, 2, RetLocInt ));
+         addInstr(env, AMD64Instr_Call( Acc_ALWAYS, (ULong)fn, 2,
+                                        mk_RetLoc_simple(RLPri_Int) ));
          addInstr(env, mk_iMOVsd_RR(hregAMD64_RAX(), dst));
          return dst;
       }
@@ -1606,7 +1701,7 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
             fn = (HWord)h_generic_calc_GetMSBs8x8;
             addInstr(env, mk_iMOVsd_RR(arg, hregAMD64_RDI()) );
             addInstr(env, AMD64Instr_Call( Acc_ALWAYS, (ULong)fn,
-                                           1, RetLocInt ));
+                                           1, mk_RetLoc_simple(RLPri_Int) ));
             /* MovxLQ is not exactly the right thing here.  We just
                need to get the bottom 8 bits of RAX into dst, and zero
                out everything else.  Assuming that the helper returns
@@ -1637,7 +1732,7 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
                                              AMD64RMI_Mem(m16_rsp),
                                              hregAMD64_RSI() )); /* 2nd arg */
             addInstr(env, AMD64Instr_Call( Acc_ALWAYS, (ULong)fn,
-                                           2, RetLocInt ));
+                                           2, mk_RetLoc_simple(RLPri_Int) ));
             /* MovxLQ is not exactly the right thing here.  We just
                need to get the bottom 16 bits of RAX into dst, and zero
                out everything else.  Assuming that the helper returns
@@ -1671,7 +1766,8 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
          HReg dst = newVRegI(env);
          HReg arg = iselIntExpr_R(env, e->Iex.Unop.arg);
          addInstr(env, mk_iMOVsd_RR(arg, hregAMD64_RDI()) );
-         addInstr(env, AMD64Instr_Call( Acc_ALWAYS, (ULong)fn, 1, RetLocInt ));
+         addInstr(env, AMD64Instr_Call( Acc_ALWAYS, (ULong)fn, 1,
+                                        mk_RetLoc_simple(RLPri_Int) ));
          addInstr(env, mk_iMOVsd_RR(hregAMD64_RAX(), dst));
          return dst;
       }
@@ -1726,14 +1822,18 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
       vassert(ty == e->Iex.CCall.retty);
 
       /* be very restrictive for now.  Only 64-bit ints allowed for
-         args, and 64 or 32 bits for return type.  Don't forget to
-         change the RetLoc if more types are allowed in future. */
+         args, and 64 or 32 bits for return type. */
       if (e->Iex.CCall.retty != Ity_I64 && e->Iex.CCall.retty != Ity_I32)
          goto irreducible;
 
       /* Marshal args, do the call. */
-      doHelperCall( env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args,
-                    RetLocInt );
+      UInt   addToSp = 0;
+      RetLoc rloc    = mk_RetLoc_INVALID();
+      doHelperCall( &addToSp, &rloc, env, NULL/*guard*/,
+                    e->Iex.CCall.cee, e->Iex.CCall.retty, e->Iex.CCall.args );
+      vassert(is_sane_RetLoc(rloc));
+      vassert(rloc.pri == RLPri_Int);
+      vassert(addToSp == 0);
 
       /* Move to dst, and zero out the top 32 bits if the result type is
          Ity_I32.  Probably overkill, but still .. */
@@ -2278,8 +2378,15 @@ static AMD64CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
       vassert(cal->Iex.CCall.retty == Ity_I64); /* else ill-typed IR */
       vassert(con->Iex.Const.con->tag == Ico_U64);
       /* Marshal args, do the call. */
-      doHelperCall( env, False, NULL, cal->Iex.CCall.cee, cal->Iex.CCall.args,
-                    RetLocInt );
+      UInt   addToSp = 0;
+      RetLoc rloc    = mk_RetLoc_INVALID();
+      doHelperCall( &addToSp, &rloc, env, NULL/*guard*/,
+                    cal->Iex.CCall.cee,
+                    cal->Iex.CCall.retty, cal->Iex.CCall.args );
+      vassert(is_sane_RetLoc(rloc));
+      vassert(rloc.pri == RLPri_Int);
+      vassert(addToSp == 0);
+      /* */
       addInstr(env, AMD64Instr_Imm64(con->Iex.Const.con->Ico.U64, tmp));
       addInstr(env, AMD64Instr_Alu64R(Aalu_CMP,
                                       AMD64RMI_Reg(hregAMD64_RAX()), tmp));
@@ -2590,7 +2697,7 @@ static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e )
       /* call the helper */
       addInstr(env, AMD64Instr_Call( Acc_ALWAYS,
                                      (ULong)(HWord)h_generic_calc_MAddF32,
-                                     4, RetLocNone ));
+                                     4, mk_RetLoc_simple(RLPri_None) ));
       /* fetch the result from memory, using %r_argp, which the
          register allocator will keep alive across the call. */
       addInstr(env, AMD64Instr_SseLdSt(True/*isLoad*/, 4, dst,
@@ -2769,7 +2876,7 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
       /* call the helper */
       addInstr(env, AMD64Instr_Call( Acc_ALWAYS,
                                      (ULong)(HWord)h_generic_calc_MAddF64,
-                                     4, RetLocNone ));
+                                     4, mk_RetLoc_simple(RLPri_None) ));
       /* fetch the result from memory, using %r_argp, which the
          register allocator will keep alive across the call. */
       addInstr(env, AMD64Instr_SseLdSt(True/*isLoad*/, 8, dst,
@@ -3491,7 +3598,7 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
                                           AMD64AMode_IR(0, hregAMD64_RDX())));
          /* call the helper */
          addInstr(env, AMD64Instr_Call( Acc_ALWAYS, (ULong)fn,
-                                        3, RetLocNone ));
+                                        3, mk_RetLoc_simple(RLPri_None) ));
          /* fetch the result from memory, using %r_argp, which the
             register allocator will keep alive across the call. */
          addInstr(env, AMD64Instr_SseLdSt(True/*isLoad*/, 16, dst,
@@ -3540,7 +3647,7 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
 
          /* call the helper */
          addInstr(env, AMD64Instr_Call( Acc_ALWAYS, (ULong)fn,
-                                        3, RetLocNone ));
+                                        3, mk_RetLoc_simple(RLPri_None) ));
          /* fetch the result from memory, using %r_argp, which the
             register allocator will keep alive across the call. */
          addInstr(env, AMD64Instr_SseLdSt(True/*isLoad*/, 16, dst,
@@ -3944,7 +4051,8 @@ static void iselDVecExpr_wrk ( /*OUT*/HReg* rHi, /*OUT*/HReg* rLo,
          addInstr(env, AMD64Instr_SseLdSt(False/*!isLoad*/, 16, argRlo,
                                           AMD64AMode_IR(48, hregAMD64_RDX())));
          /* call the helper */
-         addInstr(env, AMD64Instr_Call( Acc_ALWAYS, (ULong)fn, 3, RetLocNone ));
+         addInstr(env, AMD64Instr_Call( Acc_ALWAYS, (ULong)fn, 3,
+                                        mk_RetLoc_simple(RLPri_None) ));
          /* Prepare 3 arg regs:
             leaq 48(%r_argp), %rdi
             leaq 64(%r_argp), %rsi
@@ -3957,7 +4065,8 @@ static void iselDVecExpr_wrk ( /*OUT*/HReg* rHi, /*OUT*/HReg* rLo,
          addInstr(env, AMD64Instr_Lea64(AMD64AMode_IR(80, argp),
                                         hregAMD64_RDX()));
          /* call the helper */
-         addInstr(env, AMD64Instr_Call( Acc_ALWAYS, (ULong)fn, 3, RetLocNone ));
+         addInstr(env, AMD64Instr_Call( Acc_ALWAYS, (ULong)fn, 3,
+                                        mk_RetLoc_simple(RLPri_None) ));
          /* fetch the result from memory, using %r_argp, which the
             register allocator will keep alive across the call. */
          addInstr(env, AMD64Instr_SseLdSt(True/*isLoad*/, 16, dstHi,
@@ -4018,7 +4127,8 @@ static void iselDVecExpr_wrk ( /*OUT*/HReg* rHi, /*OUT*/HReg* rLo,
          addInstr(env, AMD64Instr_SseLdSt(False/*!isLoad*/, 16, argRhi,
                                           AMD64AMode_IR(16, hregAMD64_RDX())));
          /* call the helper */
-         addInstr(env, AMD64Instr_Call( Acc_ALWAYS, (ULong)fn, 3, RetLocNone ));
+         addInstr(env, AMD64Instr_Call( Acc_ALWAYS, (ULong)fn, 3,
+                                        mk_RetLoc_simple(RLPri_None) ));
          /* fetch the result from memory, using %r_argp, which the
             register allocator will keep alive across the call. */
          addInstr(env, AMD64Instr_SseLdSt(True/*isLoad*/, 16, dstLo,
@@ -4322,51 +4432,67 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
    /* --------- Call to DIRTY helper --------- */
    case Ist_Dirty: {
       IRDirty* d = stmt->Ist.Dirty.details;
-      Bool     passBBP = False;
-
-      if (d->nFxState == 0)
-         vassert(!d->needsBBP);
-
-      passBBP = toBool(d->nFxState > 0 && d->needsBBP);
 
       /* 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;
+      /* Throw out any return types we don't know about. */
+      Bool retty_ok = False;
       switch (retty) {
          case Ity_INVALID: /* function doesn't return anything */
-            rloc = RetLocNone; break;
-         case Ity_I64:
-         case Ity_I32: case Ity_I16: case Ity_I8:
-            rloc = RetLocInt; break;
+         case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
+         case Ity_V128:
+            retty_ok = True; break;
          default:
             break;
       }
-      if (rloc == RetLocINVALID)
+      if (!retty_ok)
          break; /* will go to stmt_fail: */
 
-      /* Marshal args, do the call, clear stack. */
-      doHelperCall( env, passBBP, d->guard, d->cee, d->args, rloc );
+      /* Marshal args, do the call, and set the return value to
+         0x555..555 if this is a conditional call that returns a value
+         and the call is skipped. */
+      UInt   addToSp = 0;
+      RetLoc rloc    = mk_RetLoc_INVALID();
+      doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args );
+      vassert(is_sane_RetLoc(rloc));
 
       /* Now figure out what to do with the returned value, if any. */
-      if (d->tmp == IRTemp_INVALID)
-         /* No return value.  Nothing to do. */
-         return;
-
-      if (retty == Ity_I64 || retty == Ity_I32 
-          || retty == Ity_I16 || retty == Ity_I8) {
-         /* The returned value is in %rax.  Park it in the register
-            associated with tmp. */
-         HReg dst = lookupIRTemp(env, d->tmp);
-         addInstr(env, mk_iMOVsd_RR(hregAMD64_RAX(),dst) );
-         return;
+      switch (retty) {
+         case Ity_INVALID: {
+            /* No return value.  Nothing to do. */
+            vassert(d->tmp == IRTemp_INVALID);
+            vassert(rloc.pri == RLPri_None);
+            vassert(addToSp == 0);
+            return;
+         }
+         case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8: {
+            /* The returned value is in %rax.  Park it in the register
+               associated with tmp. */
+            vassert(rloc.pri == RLPri_Int);
+            vassert(addToSp == 0);
+            HReg dst = lookupIRTemp(env, d->tmp);
+            addInstr(env, mk_iMOVsd_RR(hregAMD64_RAX(),dst) );
+            return;
+         }
+         case Ity_V128: {
+            /* The returned value is on the stack, and *retloc tells
+               us where.  Fish it off the stack and then move the
+               stack pointer upwards to clear it, as directed by
+               doHelperCall. */
+            vassert(rloc.pri == RLPri_V128SpRel);
+            vassert(addToSp >= 16);
+            HReg        dst = lookupIRTemp(env, d->tmp);
+            AMD64AMode* am  = AMD64AMode_IR(rloc.spOff, hregAMD64_RSP());
+            addInstr(env, AMD64Instr_SseLdSt( True/*load*/, 16, dst, am ));
+            add_to_rsp(env, addToSp);
+            return;
+         }
+         default:
+            /*NOTREACHED*/
+            vassert(0);
       }
       break;
    }
index 71b68a2736012823dfbf90f774e11bd67cb51e5c..2eee278d5812788307c470c9f8a03fb99bd6186a 100644 (file)
@@ -1236,7 +1236,7 @@ ARMInstr* ARMInstr_Call ( ARMCondCode cond, HWord target, Int nArgRegs,
    i->ARMin.Call.target   = target;
    i->ARMin.Call.nArgRegs = nArgRegs;
    i->ARMin.Call.rloc     = rloc;
-   vassert(rloc != RetLocINVALID);
+   vassert(is_sane_RetLoc(rloc));
    return i;
 }
 ARMInstr* ARMInstr_Mul ( ARMMulOp op ) {
@@ -3398,7 +3398,7 @@ Int emit_ARMInstr ( /*MB_MOD*/Bool* is_profInc,
             the call doesn't happen, just do the simple thing and emit
             straight-line code.  We hope this is the common case. */
          if (i->ARMin.Call.cond == ARMcc_AL/*call always happens*/
-             || i->ARMin.Call.rloc == RetLocNone/*no fixup action*/) {
+             || i->ARMin.Call.rloc.pri == RLPri_None/*no fixup action*/) {
             // r"scratchNo" = &target
             p = imm32_to_iregNo( (UInt*)p,
                                  scratchNo, (UInt)i->ARMin.Call.target );
@@ -3451,17 +3451,17 @@ Int emit_ARMInstr ( /*MB_MOD*/Bool* is_profInc,
                = XX______(1 ^ i->ARMin.Call.cond, X1010) | (delta & 0xFFFFFF);
 
             /* Do the 'else' actions */
-            switch (i->ARMin.Call.rloc) {
-               case RetLocInt:
+            switch (i->ARMin.Call.rloc.pri) {
+               case RLPri_Int:
                   p = imm32_to_iregNo_EXACTLY2(p, /*r*/0, 0x55555555);
                   break;
-               case RetLoc2Int:
+               case RLPri_2Int:
                   vassert(0); //ATC
                   p = imm32_to_iregNo_EXACTLY2(p, /*r*/0, 0x55555555);
                   /* mov r1, r0 */
                   *p++ = 0xE1A01000;
                   break;
-               case RetLocNone: case RetLocINVALID: default:
+               case RLPri_None: case RLPri_INVALID: default:
                   vassert(0);
             }
 
index 0f1539e6b1f4f02d555a31a1af953ccd3162dd44..18c61228d446d96d8fec0023abc3bc02d72b078e 100644 (file)
@@ -361,6 +361,12 @@ void set_VFP_rounding_mode ( ISelEnv* env, IRExpr* mode )
 static
 Bool mightRequireFixedRegs ( IRExpr* e )
 {
+   if (UNLIKELY(is_IRExprP__VECRET_or_BBPTR(e))) {
+      // These are always "safe" -- either a copy of r13(sp) in some
+      // arbitrary vreg, or a copy of r8, respectively.
+      return False;
+   }
+   /* Else it's a "normal" expression. */
    switch (e->tag) {
    case Iex_RdTmp: case Iex_Const: case Iex_Get:
       return False;
@@ -370,16 +376,20 @@ Bool mightRequireFixedRegs ( IRExpr* e )
 }
 
 
-/* Do a complete function call.  guard is a Ity_Bit expression
+/* Do a complete function call.  |guard| is a Ity_Bit expression
    indicating whether or not the call happens.  If guard==NULL, the
-   call is unconditional.  Returns True iff it managed to handle this
+   call is unconditional.  |retloc| is set to indicate where the
+   return value is after the call.  The caller (of this fn) must
+   generate code to add |stackAdjustAfterCall| to the stack pointer
+   after the call is done.  Returns True iff it managed to handle this
    combination of arg/return types, else returns False. */
 
 static
-Bool doHelperCall ( ISelEnv* env,
-                    Bool passBBP,
-                    IRExpr* guard, IRCallee* cee, IRExpr** args,
-                    RetLoc rloc )
+Bool doHelperCall ( /*OUT*/UInt*   stackAdjustAfterCall,
+                    /*OUT*/RetLoc* retloc,
+                    ISelEnv* env,
+                    IRExpr* guard,
+                    IRCallee* cee, IRType retTy, IRExpr** args )
 {
    ARMCondCode cc;
    HReg        argregs[ARM_N_ARGREGS];
@@ -390,10 +400,16 @@ Bool doHelperCall ( ISelEnv* env,
 
    vassert(ARM_N_ARGREGS == 4);
 
-   /* Marshal args for a call and do the call.
+   /* Set default returns.  We'll update them later if needed. */
+   *stackAdjustAfterCall = 0;
+   *retloc               = mk_RetLoc_INVALID();
 
-      If passBBP is True, r8 (the baseblock pointer) is to be passed
-      as the first arg.
+   /* These are used for cross-checking that IR-level constraints on
+      the use of IRExprP__VECRET and IRExprP__BBPTR are observed. */
+   UInt nVECRETs = 0;
+   UInt nBBPTRs  = 0;
+
+   /* Marshal args for a call and do the call.
 
       This function only deals with a tiny set of possibilities, which
       cover all helpers in practice.  The restrictions are that only
@@ -401,6 +417,17 @@ Bool doHelperCall ( ISelEnv* env,
       x 32 integer bits in total can be passed.  In fact the only
       supported arg types are I32 and I64.
 
+      The return type can be I{64,32} or V128.  In the V128 case, it
+      is expected that |args| will contain the special value
+      IRExprP__VECRET, in which case this routine generates code to
+      allocate space on the stack for the vector return value.  Since
+      we are not passing any scalars on the stack, it is enough to
+      preallocate the return space before marshalling any arguments,
+      in this case.
+
+      |args| may also contain IRExprP__BBPTR, in which case the
+      value in r8 is passed as the corresponding argument.
+
       Generating code which is both efficient and correct when
       parameters are to be passed in registers is difficult, for the
       reasons elaborated in detail in comments attached to
@@ -441,8 +468,15 @@ Bool doHelperCall ( ISelEnv* env,
       ignore it. */
 
    n_args = 0;
-   for (i = 0; args[i]; i++)
+   for (i = 0; args[i]; i++) {
+      IRExpr* arg = args[i];
+      if (UNLIKELY(arg == IRExprP__VECRET)) {
+         nVECRETs++;
+      } else if (UNLIKELY(arg == IRExprP__BBPTR)) {
+         nBBPTRs++;
+      }
       n_args++;
+   }
 
    argregs[0] = hregARM_R0();
    argregs[1] = hregARM_R1();
@@ -477,6 +511,12 @@ Bool doHelperCall ( ISelEnv* env,
          }
       }
    }
+
+   if (go_fast) {
+      if (retTy == Ity_V128 || retTy == Ity_V256)
+         go_fast = False;
+   }
+
    /* At this point the scheme to use has been established.  Generate
       code to get the arg values into the argument rregs.  If we run
       out of arg regs, give up. */
@@ -485,19 +525,20 @@ Bool doHelperCall ( ISelEnv* env,
 
       /* FAST SCHEME */
       nextArgReg = 0;
-      if (passBBP) {
-         addInstr(env, mk_iMOVds_RR( argregs[nextArgReg],
-                                     hregARM_R8() ));
-         nextArgReg++;
-      }
 
       for (i = 0; i < n_args; i++) {
-         IRType aTy = typeOfIRExpr(env->type_env, args[i]);
+         IRExpr* arg = args[i];
+
+         IRType  aTy = Ity_INVALID;
+         if (LIKELY(!is_IRExprP__VECRET_or_BBPTR(arg)))
+            aTy = typeOfIRExpr(env->type_env, arg);
+
          if (nextArgReg >= ARM_N_ARGREGS)
             return False; /* out of argregs */
+
          if (aTy == Ity_I32) {
             addInstr(env, mk_iMOVds_RR( argregs[nextArgReg],
-                                        iselIntExpr_R(env, args[i]) ));
+                                        iselIntExpr_R(env, arg) ));
             nextArgReg++;
          }
          else if (aTy == Ity_I64) {
@@ -514,12 +555,22 @@ Bool doHelperCall ( ISelEnv* env,
             if (nextArgReg >= ARM_N_ARGREGS)
                return False; /* out of argregs */
             HReg raHi, raLo;
-            iselInt64Expr(&raHi, &raLo, env, args[i]);
+            iselInt64Expr(&raHi, &raLo, env, arg);
             addInstr(env, mk_iMOVds_RR( argregs[nextArgReg], raLo ));
             nextArgReg++;
             addInstr(env, mk_iMOVds_RR( argregs[nextArgReg], raHi ));
             nextArgReg++;
          }
+         else if (arg == IRExprP__BBPTR) {
+            vassert(0); //ATC
+            addInstr(env, mk_iMOVds_RR( argregs[nextArgReg],
+                                        hregARM_R8() ));
+            nextArgReg++;
+         }
+         else if (arg == IRExprP__VECRET) {
+            // If this happens, it denotes ill-formed IR
+            vassert(0);
+         }
          else
             return False; /* unhandled arg type */
       }
@@ -532,19 +583,16 @@ Bool doHelperCall ( ISelEnv* env,
       /* SLOW SCHEME; move via temporaries */
       nextArgReg = 0;
 
-      if (passBBP) {
-         /* This is pretty stupid; better to move directly to r0
-            after the rest of the args are done. */
-         tmpregs[nextArgReg] = newVRegI(env);
-         addInstr(env, mk_iMOVds_RR( tmpregs[nextArgReg],
-                                     hregARM_R8() ));
-         nextArgReg++;
-      }
-
       for (i = 0; i < n_args; i++) {
-         IRType aTy = typeOfIRExpr(env->type_env, args[i]);
+         IRExpr* arg = args[i];
+
+         IRType  aTy = Ity_INVALID;
+         if (LIKELY(!is_IRExprP__VECRET_or_BBPTR(arg)))
+            aTy  = typeOfIRExpr(env->type_env, arg);
+
          if (nextArgReg >= ARM_N_ARGREGS)
             return False; /* out of argregs */
+
          if (aTy == Ity_I32) {
             tmpregs[nextArgReg] = iselIntExpr_R(env, args[i]);
             nextArgReg++;
@@ -562,6 +610,17 @@ Bool doHelperCall ( ISelEnv* env,
             tmpregs[nextArgReg] = raHi;
             nextArgReg++;
          }
+         else if (arg == IRExprP__BBPTR) {
+            vassert(0); //ATC
+            tmpregs[nextArgReg] = hregARM_R8();
+            nextArgReg++;
+         }
+         else if (arg == IRExprP__VECRET) {
+            // If this happens, it denotes ill-formed IR
+            vassert(0);
+         }
+         else
+            return False; /* unhandled arg type */
       }
 
       /* Now we can compute the condition.  We can't do it earlier
@@ -595,7 +654,41 @@ Bool doHelperCall ( ISelEnv* env,
    /* Should be assured by checks above */
    vassert(nextArgReg <= ARM_N_ARGREGS);
 
-   target = (HWord)Ptr_to_ULong(cee->addr);
+   /* Do final checks, set the return values, and generate the call
+      instruction proper. */
+   vassert(nBBPTRs == 0 || nBBPTRs == 1);
+   vassert(nVECRETs == (retTy == Ity_V128 || retTy == Ity_V256) ? 1 : 0);
+   vassert(*stackAdjustAfterCall == 0);
+   vassert(is_RetLoc_INVALID(*retloc));
+   switch (retTy) {
+         case Ity_INVALID:
+            /* Function doesn't return a value. */
+            *retloc = mk_RetLoc_simple(RLPri_None);
+            break;
+         case Ity_I64:
+            *retloc = mk_RetLoc_simple(RLPri_2Int);
+            break;
+         case Ity_I32: case Ity_I16: case Ity_I8:
+            *retloc = mk_RetLoc_simple(RLPri_Int);
+            break;
+         case Ity_V128:
+            vassert(0); // ATC
+            *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 0);
+            *stackAdjustAfterCall = 16;
+            break;
+         case Ity_V256:
+            vassert(0); // ATC
+            *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 0);
+            *stackAdjustAfterCall = 32;
+            break;
+         default:
+            /* IR can denote other possible return types, but we don't
+               handle those here. */
+           vassert(0);
+   }
+
+   /* Finally, generate the call itself.  This needs the *retloc value
+      set in the switch above, which is why it's at the end. */
 
    /* nextArgReg doles out argument registers.  Since these are
       assigned in the order r0, r1, r2, r3, its numeric value at this
@@ -615,8 +708,8 @@ Bool doHelperCall ( ISelEnv* env,
       instruction, a bitmask indicating which of r0/1/2/3 carry live
       values.  But that's too much hassle. */
 
-   /* Finally, the call itself. */
-   addInstr(env, ARMInstr_Call( cc, target, nextArgReg, rloc ));
+   target = (HWord)Ptr_to_ULong(cee->addr);
+   addInstr(env, ARMInstr_Call( cc, target, nextArgReg, *retloc ));
 
    return True; /* success */
 }
@@ -1391,7 +1484,7 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
          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, RetLocInt ));
+                                      2, mk_RetLoc_simple(RLPri_Int) ));
          addInstr(env, mk_iMOVds_RR(res, hregARM_R0()));
          return res;
       }
@@ -1680,7 +1773,7 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
          HReg res = newVRegI(env);
          addInstr(env, mk_iMOVds_RR(hregARM_R0(), arg));
          addInstr(env, ARMInstr_Call( ARMcc_AL, (HWord)Ptr_to_ULong(fn),
-                                      1, RetLocInt ));
+                                      1, mk_RetLoc_simple(RLPri_Int) ));
          addInstr(env, mk_iMOVds_RR(res, hregARM_R0()));
          return res;
       }
@@ -1741,10 +1834,16 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
          goto irreducible;
 
       /* Marshal args, do the call, clear stack. */
-      Bool ok = doHelperCall( env, False,
-                              NULL, e->Iex.CCall.cee, e->Iex.CCall.args,
-                              RetLocInt );
+      UInt   addToSp = 0;
+      RetLoc rloc    = mk_RetLoc_INVALID();
+      Bool   ok      = doHelperCall( &addToSp, &rloc, env, NULL/*guard*/,
+                                     e->Iex.CCall.cee, e->Iex.CCall.retty,
+                                     e->Iex.CCall.args );
+      /* */
       if (ok) {
+         vassert(is_sane_RetLoc(rloc));
+         vassert(rloc.pri == RLPri_Int);
+         vassert(addToSp == 0);
          addInstr(env, mk_iMOVds_RR(dst, hregARM_R0()));
          return dst;
       }
@@ -5874,69 +5973,96 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
    /* call complex ("dirty") helper function */
    case Ist_Dirty: {
       IRDirty* d = stmt->Ist.Dirty.details;
-      Bool     passBBP = False;
-
-      if (d->nFxState == 0)
-         vassert(!d->needsBBP);
-
-      passBBP = toBool(d->nFxState > 0 && d->needsBBP);
 
       /* 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;
+      Bool retty_ok = False;
       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;
+         case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
+         //case Ity_V128: //ATC
+            retty_ok = True; break;
          default:
             break;
       }
-      if (rloc == RetLocINVALID)
+      if (!retty_ok)
          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: */
+      /* Marshal args, do the call, and set the return value to 0x555..555
+         if this is a conditional call that returns a value and the
+         call is skipped. */
+      UInt   addToSp = 0;
+      RetLoc rloc    = mk_RetLoc_INVALID();
+      doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args );
+      vassert(is_sane_RetLoc(rloc));
 
       /* Now figure out what to do with the returned value, if any. */
-      if (d->tmp == IRTemp_INVALID)
-         /* No return value.  Nothing to do. */
-         return;
-
-      if (retty == Ity_I64) {
-         if (env->hwcaps & VEX_HWCAPS_ARM_NEON) {
-            HReg tmp = lookupIRTemp(env, d->tmp);
-            addInstr(env, ARMInstr_VXferD(True, tmp, hregARM_R1(),
-                                                     hregARM_R0()));
-         } else {
-            HReg dstHi, dstLo;
-            /* The returned value is in r1:r0.  Park it in the
-               register-pair associated with tmp. */
-            lookupIRTemp64( &dstHi, &dstLo, env, d->tmp);
-            addInstr(env, mk_iMOVds_RR(dstHi, hregARM_R1()) );
-            addInstr(env, mk_iMOVds_RR(dstLo, hregARM_R0()) );
+      switch (retty) {
+         case Ity_INVALID: {
+            /* No return value.  Nothing to do. */
+            vassert(d->tmp == IRTemp_INVALID);
+            vassert(rloc.pri == RLPri_None);
+            vassert(addToSp == 0);
+            return;
          }
-         return;
-      }
-      if (retty == Ity_I32 || retty == Ity_I16 || retty == Ity_I8) {
-         /* The returned value is in r0.  Park it in the register
-            associated with tmp. */
-         HReg dst = lookupIRTemp(env, d->tmp);
-         addInstr(env, mk_iMOVds_RR(dst, hregARM_R0()) );
-         return;
+         case Ity_I64: {
+            vassert(rloc.pri == RLPri_2Int);
+            vassert(addToSp == 0);
+            if (env->hwcaps & VEX_HWCAPS_ARM_NEON) {
+               HReg tmp = lookupIRTemp(env, d->tmp);
+               addInstr(env, ARMInstr_VXferD(True, tmp, hregARM_R1(),
+                                                        hregARM_R0()));
+            } else {
+               HReg dstHi, dstLo;
+               /* The returned value is in r1:r0.  Park it in the
+                  register-pair associated with tmp. */
+               lookupIRTemp64( &dstHi, &dstLo, env, d->tmp);
+               addInstr(env, mk_iMOVds_RR(dstHi, hregARM_R1()) );
+               addInstr(env, mk_iMOVds_RR(dstLo, hregARM_R0()) );
+            }
+            return;
+         }
+         case Ity_I32: case Ity_I16: case Ity_I8: {
+            vassert(rloc.pri == RLPri_Int);
+            vassert(addToSp == 0);
+            /* The returned value is in r0.  Park it in the register
+               associated with tmp. */
+            HReg dst = lookupIRTemp(env, d->tmp);
+            addInstr(env, mk_iMOVds_RR(dst, hregARM_R0()) );
+            return;
+         }
+         case Ity_V128: {
+            vassert(0); // ATC.  The code that this produces really
+            // needs to be looked at, to verify correctness.
+            // I don't think this can ever happen though, since the
+            // ARM front end never produces 128-bit loads/stores.
+            // Hence the following is mostly theoretical.
+            /* The returned value is on the stack, and *retloc tells
+               us where.  Fish it off the stack and then move the
+               stack pointer upwards to clear it, as directed by
+               doHelperCall. */
+            vassert(rloc.pri == RLPri_V128SpRel);
+            vassert(rloc.spOff < 256); // else ARMRI84_I84(_,0) can't encode it
+            vassert(addToSp >= 16);
+            vassert(addToSp < 256); // ditto reason as for rloc.spOff
+            HReg dst = lookupIRTemp(env, d->tmp);
+            HReg tmp = newVRegI(env);
+            HReg r13 = hregARM_R13(); // sp
+            addInstr(env, ARMInstr_Alu(ARMalu_ADD,
+                                       tmp, r13, ARMRI84_I84(rloc.spOff,0)));
+            ARMAModeN* am = mkARMAModeN_R(tmp);
+            addInstr(env, ARMInstr_NLdStQ(True/*load*/, dst, am));
+            addInstr(env, ARMInstr_Alu(ARMalu_ADD,
+                                       r13, r13, ARMRI84_I84(addToSp,0)));
+            return;
+         }
+         default:
+            /*NOTREACHED*/
+            vassert(0);
       }
-
       break;
    }
 
index 7e1a1b2fbb7212d6b2b45d28fe412fb2858e6992..025670bce54a976748363ce12fb9989d141c91d8 100644 (file)
@@ -224,12 +224,21 @@ void addHInstr ( HInstrArray* ha, HInstr* instr )
 
 void ppRetLoc ( RetLoc ska )
 {
-   switch (ska) {
-      case RetLocINVALID: vex_printf("RetLocINVALID"); return;
-      case RetLocNone:    vex_printf("RetLocNone");    return;
-      case RetLocInt:     vex_printf("RetLocInt");     return;
-      case RetLoc2Int:    vex_printf("RetLoc2Int");    return;
-      default:            vpanic("ppRetLoc");
+   switch (ska.pri) {
+      case RLPri_INVALID:
+         vex_printf("RLPri_INVALID"); return;
+      case RLPri_None:
+         vex_printf("RLPri_None");    return;
+      case RLPri_Int:
+         vex_printf("RLPri_Int");     return;
+      case RLPri_2Int:
+         vex_printf("RLPri_2Int");    return;
+      case RLPri_V128SpRel:
+         vex_printf("RLPri_V128SpRel(%d)", ska.spOff); return;
+      case RLPri_V256SpRel:
+         vex_printf("RLPri_V256SpRel(%d)", ska.spOff); return;
+      default:
+         vpanic("ppRetLoc");
    }
 }
 
index 39bd97f59e2cc0b020a13f9736ee6c65b92a7f70..096c9673f6ff91357bb53fa8ce224a7564c926ba 100644 (file)
@@ -256,15 +256,58 @@ extern void         addHInstr ( HInstrArray*, HInstr* );
 
 typedef
    enum {
-      RetLocINVALID, /* INVALID */
-      RetLocNone,    /* no return value (a.k.a C "void") */
-      RetLocInt,     /* in the primary int return reg */
-      RetLoc2Int     /* in both primary and secondary int ret regs */
+      RLPri_INVALID,   /* INVALID */
+      RLPri_None,      /* no return value (a.k.a C "void") */
+      RLPri_Int,       /* in the primary int return reg */
+      RLPri_2Int,      /* in both primary and secondary int ret regs */
+      RLPri_V128SpRel, /* 128-bit value, on the stack */
+      RLPri_V256SpRel  /* 256-bit value, on the stack */
+   }
+   RetLocPrimary;
+
+typedef
+   struct {
+      /* Primary description */
+      RetLocPrimary pri;
+      /* For .pri == RLPri_V128SpRel or RLPri_V256SpRel only, gives
+         the offset of the lowest addressed byte of the value,
+         relative to the stack pointer.  For all other .how values,
+         has no meaning and should be zero. */
+      Int spOff;
    }
    RetLoc;
 
 extern void ppRetLoc ( RetLoc rloc );
 
+static inline RetLoc mk_RetLoc_simple ( RetLocPrimary pri ) {
+   vassert(pri >= RLPri_INVALID && pri <= RLPri_2Int);
+   return (RetLoc){pri, 0};
+}
+
+static inline RetLoc mk_RetLoc_spRel ( RetLocPrimary pri, Int off ) {
+   vassert(pri >= RLPri_V128SpRel && pri <= RLPri_V256SpRel);
+   return (RetLoc){pri, off};
+}
+
+static inline Bool is_sane_RetLoc ( RetLoc rloc ) {
+   switch (rloc.pri) {
+      case RLPri_None: case RLPri_Int: case RLPri_2Int:
+         return rloc.spOff == 0;
+      case RLPri_V128SpRel: case RLPri_V256SpRel:
+         return True;
+      default:
+         return False;
+   }
+}
+
+static inline RetLoc mk_RetLoc_INVALID ( void ) {
+   return (RetLoc){RLPri_INVALID, 0};
+}
+
+static inline Bool is_RetLoc_INVALID ( RetLoc rl ) {
+   return rl.pri == RLPri_INVALID && rl.spOff == 0;
+}
+
 
 /*---------------------------------------------------------*/
 /*--- Reg alloc: TODO: move somewhere else              ---*/
index b6ea1751f2d3a935e66dad2e8302776fe96d3d06..d254a267d1fc1b9d50271a1e959107204cbff99f 100644 (file)
@@ -1285,7 +1285,7 @@ MIPSInstr *MIPSInstr_Call ( MIPSCondCode cond, Addr64 target, UInt argiregs,
    mask = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9)
           | (1 << 10) | (1 << 11);
    vassert(0 == (argiregs & ~mask));
-   vassert(rloc != RetLocINVALID);
+   vassert(is_sane_RetLoc(rloc));
    return i;
 }
 
@@ -1303,7 +1303,7 @@ MIPSInstr *MIPSInstr_CallAlways ( MIPSCondCode cond, Addr64 target,
    mask = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9)
           | (1 << 10) | (1 << 11);
    vassert(0 == (argiregs & ~mask));
-   vassert(rloc != RetLocINVALID);
+   vassert(is_sane_RetLoc(rloc));
    return i;
 }
 
@@ -3286,7 +3286,8 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc,
       }
 
       case Min_Call: {
-         if (i->Min.Call.cond != MIPScc_AL && i->Min.Call.rloc != RetLocNone) {
+         if (i->Min.Call.cond != MIPScc_AL
+             && i->Min.Call.rloc.pri != RLPri_None) {
             /* The call might not happen (it isn't unconditional) and
                it returns a result.  In this case we will need to
                generate a control flow diamond to put 0x555..555 in
index 0c573afd07e81543f52f88e4cf8295fad1d72b45..42cb2a673d6c624cd02809900c3e0ba5fee156b5 100644 (file)
@@ -379,12 +379,18 @@ static HReg mk_LoadRR32toFPR(ISelEnv * env, HReg r_srcHi, HReg r_srcLo)
    return fr_dst;
 }
 
-/* Do a complete function call.  guard is a Ity_Bit expression
+/* Do a complete function call.  |guard| is a Ity_Bit expression
    indicating whether or not the call happens.  If guard==NULL, the
-   call is unconditional. */
-
-static void doHelperCall(ISelEnv * env, Bool passBBP, IRExpr * guard,
-                         IRCallee * cee, IRExpr ** args, RetLoc rloc)
+   call is unconditional.  |retloc| is set to indicate where the
+   return value is after the call.  The caller (of this fn) must
+   generate code to add |stackAdjustAfterCall| to the stack pointer
+   after the call is done. */
+
+static void doHelperCall(/*OUT*/UInt*   stackAdjustAfterCall,
+                         /*OUT*/RetLoc* retloc,
+                         ISelEnv* env,
+                         IRExpr* guard,
+                         IRCallee* cee, IRType retTy, IRExpr** args )
 {
    MIPSCondCode cc;
    HReg argregs[MIPS_N_REGPARMS];
@@ -392,9 +398,17 @@ static void doHelperCall(ISelEnv * env, Bool passBBP, IRExpr * guard,
    Bool go_fast;
    Int n_args, i, argreg;
    UInt argiregs;
-   ULong target;
    HReg src = INVALID_HREG;
 
+   /* Set default returns.  We'll update them later if needed. */
+   *stackAdjustAfterCall = 0;
+   *retloc               = mk_RetLoc_INVALID();
+
+   /* These are used for cross-checking that IR-level constraints on
+      the use of IRExprP__VECRET and IRExprP__BBPTR are observed. */
+   UInt nVECRETs = 0;
+   UInt nBBPTRs  = 0;
+
    /* MIPS O32 calling convention: up to four registers ($a0 ... $a3)
       are allowed to be used for passing integer arguments. They correspond
       to regs GPR4 ... GPR7. Note that the cee->regparms field is meaningless
@@ -406,11 +420,31 @@ static void doHelperCall(ISelEnv * env, Bool passBBP, IRExpr * guard,
       to regs GPR4 ... GPR11. Note that the cee->regparms field is meaningless
       on MIPS host (since we only implement one calling convention) and so we
       always ignore it. */
+
+   /* The return type can be I{64,32,16,8} or V{128,256}.  In the
+      latter two cases, it is expected that |args| will contain the
+      special value IRExprP__VECRET, in which case this routine
+      generates code to allocate space on the stack for the vector
+      return value.  Since we are not passing any scalars on the
+      stack, it is enough to preallocate the return space before
+      marshalling any arguments, in this case.
+
+      |args| may also contain IRExprP__BBPTR, in which case the value
+      in the guest state pointer register is passed as the
+      corresponding argument. */
+
    n_args = 0;
-   for (i = 0; args[i]; i++)
+   for (i = 0; args[i]; i++) {
+      IRExpr* arg = args[i];
+      if (UNLIKELY(arg == IRExprP__VECRET)) {
+         nVECRETs++;
+      } else if (UNLIKELY(arg == IRExprP__BBPTR)) {
+         nBBPTRs++;
+      }
       n_args++;
+   }
 
-   if (MIPS_N_REGPARMS < n_args + (passBBP ? 1 : 0)) {
+   if (n_args > MIPS_N_REGPARMS) {
       vpanic("doHelperCall(MIPS): cannot currently handle > 4 or 8 args");
    }
    if (mode64) {
@@ -423,22 +457,30 @@ static void doHelperCall(ISelEnv * env, Bool passBBP, IRExpr * guard,
       argregs[6] = hregMIPS_GPR10(mode64);
       argregs[7] = hregMIPS_GPR11(mode64);
       argiregs = 0;
+      tmpregs[0] = tmpregs[1] = tmpregs[2] =
+      tmpregs[3] = tmpregs[4] = tmpregs[5] =
+      tmpregs[6] = tmpregs[7] = INVALID_HREG;
    } else {
       argregs[0] = hregMIPS_GPR4(mode64);
       argregs[1] = hregMIPS_GPR5(mode64);
       argregs[2] = hregMIPS_GPR6(mode64);
       argregs[3] = hregMIPS_GPR7(mode64);
       argiregs = 0;
+      tmpregs[0] = tmpregs[1] = tmpregs[2] = tmpregs[3] = INVALID_HREG;
    }
 
-   tmpregs[0] = tmpregs[1] = tmpregs[2] = tmpregs[3] = INVALID_HREG;
-
    /* First decide which scheme (slow or fast) is to be used. First assume the
       fast scheme, and select slow if any contraindications (wow) appear. */
 
    go_fast = True;
 
-   if (guard) {
+   /* We'll need space on the stack for the return value.  Avoid
+      possible complications with nested calls by using the slow
+      scheme. */
+   if (retTy == Ity_V128 || retTy == Ity_V256)
+      go_fast = False;
+
+   if (go_fast && guard) {
       if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1
           && guard->Iex.Const.con->Ico.U1 == True) {
          /* unconditional */
@@ -462,66 +504,79 @@ static void doHelperCall(ISelEnv * env, Bool passBBP, IRExpr * guard,
    if (go_fast) {
       /* FAST SCHEME */
       argreg = 0;
-      if (passBBP) {
-         argiregs |= (1 << (argreg + 4));
-         addInstr(env, mk_iMOVds_RR(argregs[argreg],
-                  GuestStatePointer(mode64)));
-         argreg++;
-      }
 
       for (i = 0; i < n_args; i++) {
+         IRExpr* arg = args[i];
          vassert(argreg < MIPS_N_REGPARMS);
-         vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32
-                 || typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
-         if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32 || mode64) {
+
+         IRType  aTy = Ity_INVALID;
+         if (LIKELY(!is_IRExprP__VECRET_or_BBPTR(arg)))
+            aTy = typeOfIRExpr(env->type_env, arg);
+
+         if (aTy == Ity_I32 || mode64) {
             argiregs |= (1 << (argreg + 4));
-            addInstr(env, mk_iMOVds_RR(argregs[argreg], iselWordExpr_R(env,
-                     args[i])));
-         } else {  /* Ity_I64 */
+            addInstr(env, mk_iMOVds_RR(argregs[argreg],
+                                       iselWordExpr_R(env, arg)));
+            argreg++;
+         } else if (aTy == Ity_I64) {  /* Ity_I64 */
             if (argreg & 1) {
                argreg++;
                argiregs |= (1 << (argreg + 4));
             }
             HReg rHi, rLo;
-            iselInt64Expr(&rHi, &rLo, env, args[i]);
+            iselInt64Expr(&rHi, &rLo, env, arg);
             argiregs |= (1 << (argreg + 4));
             addInstr(env, mk_iMOVds_RR( argregs[argreg++], rHi ));
             argiregs |= (1 << (argreg + 4));
             addInstr(env, mk_iMOVds_RR( argregs[argreg], rLo));
+            argreg++;
+         } else if (arg == IRExprP__BBPTR) {
+            vassert(0);  // ATC
+            addInstr(env, mk_iMOVds_RR(argregs[argreg],
+                                       GuestStatePointer(mode64)));
+            argreg++;
+         } else if (arg == IRExprP__VECRET) {
+            // If this happens, it denotes ill-formed IR.
+            vassert(0);
          }
-         argreg++;
       }
       /* Fast scheme only applies for unconditional calls.  Hence: */
       cc = MIPScc_AL;
    } else {
       /* SLOW SCHEME; move via temporaries */
       argreg = 0;
-      if (passBBP) {
-         /* This is pretty stupid; better to move directly to r3
-            after the rest of the args are done. */
-         tmpregs[argreg] = newVRegI(env);
-         addInstr(env, mk_iMOVds_RR(tmpregs[argreg],
-                  GuestStatePointer(mode64)));
-         argreg++;
-      }
+
       for (i = 0; i < n_args; i++) {
          vassert(argreg < MIPS_N_REGPARMS);
-         vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32
-                 || typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
-         if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32 || mode64) {
-            tmpregs[argreg] = iselWordExpr_R(env, args[i]);
-         } else {  /* Ity_I64 */
+         IRExpr* arg = args[i];
+
+         IRType  aTy = Ity_INVALID;
+         if (LIKELY(!is_IRExprP__VECRET_or_BBPTR(arg)))
+            aTy  = typeOfIRExpr(env->type_env, arg);
+
+         if (aTy == Ity_I32 || mode64) {
+            tmpregs[argreg] = iselWordExpr_R(env, arg);
+            argreg++;
+         } else if (aTy == Ity_I64) {  /* Ity_I64 */
             if (argreg & 1)
                argreg++;
             if (argreg + 1 >= MIPS_N_REGPARMS)
                vassert(0);  /* out of argregs */
             HReg raHi, raLo;
-            iselInt64Expr(&raHi, &raLo, env, args[i]);
+            iselInt64Expr(&raHi, &raLo, env, arg);
             tmpregs[argreg] = raLo;
             argreg++;
             tmpregs[argreg] = raHi;
+            argreg++;
+         } else if (arg == IRExprP__BBPTR) {
+            vassert(0);  // ATC
+            tmpregs[argreg] = GuestStatePointer(mode64);
+            argreg++;
+         }
+         else if (arg == IRExprP__VECRET) {
+            // If this happens, it denotes ill-formed IR
+            vassert(0);
          }
-         argreg++;
       }
 
       /* Now we can compute the condition.  We can't do it earlier
@@ -549,14 +604,49 @@ static void doHelperCall(ISelEnv * env, Bool passBBP, IRExpr * guard,
       }
    }
 
-   target = mode64 ? Ptr_to_ULong(cee->addr) :
-                     toUInt(Ptr_to_ULong(cee->addr));
+   /* Do final checks, set the return values, and generate the call
+      instruction proper. */
+   vassert(nBBPTRs == 0 || nBBPTRs == 1);
+   vassert(nVECRETs == (retTy == Ity_V128 || retTy == Ity_V256) ? 1 : 0);
+   vassert(*stackAdjustAfterCall == 0);
+   vassert(is_RetLoc_INVALID(*retloc));
+   switch (retTy) {
+      case Ity_INVALID:
+         /* Function doesn't return a value. */
+         *retloc = mk_RetLoc_simple(RLPri_None);
+         break;
+      case Ity_I64:
+         *retloc = mk_RetLoc_simple(mode64 ? RLPri_Int : RLPri_2Int);
+         break;
+      case Ity_I32: case Ity_I16: case Ity_I8:
+         *retloc = mk_RetLoc_simple(RLPri_Int);
+         break;
+      case Ity_V128:
+         vassert(0); // ATC
+         *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 0);
+         *stackAdjustAfterCall = 16;
+         break;
+      case Ity_V256:
+         vassert(0); // ATC
+         *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 0);
+         *stackAdjustAfterCall = 32;
+         break;
+      default:
+         /* IR can denote other possible return types, but we don't
+            handle those here. */
+        vassert(0);
+   }
 
-   /* Finally, the call itself. */
+   ULong target = mode64 ? Ptr_to_ULong(cee->addr) :
+                           toUInt(Ptr_to_ULong(cee->addr));
+
+   /* Finally, generate the call itself.  This needs the *retloc value
+      set in the switch above, which is why it's at the end. */
    if (cc == MIPScc_AL)
-      addInstr(env, MIPSInstr_CallAlways(cc, (Addr64)target, argiregs, rloc));
+      addInstr(env, MIPSInstr_CallAlways(cc, (Addr64)target, argiregs,
+                                         *retloc));
    else
-      addInstr(env, MIPSInstr_Call(cc, (Addr64)target, argiregs, src, rloc));
+      addInstr(env, MIPSInstr_Call(cc, (Addr64)target, argiregs, src, *retloc));
 }
 
 /*---------------------------------------------------------*/
@@ -1244,12 +1334,13 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e)
          }
 
          /* What's the retloc? */
-         RetLoc rloc = RetLocINVALID;
+         RetLoc rloc = mk_RetLoc_INVALID();
          if (ty == Ity_I32) {
-            rloc = RetLocInt;
+            rloc = mk_RetLoc_simple(RLPri_Int);
          }
          else if (ty == Ity_I64) {
-            rloc = mode64 ? RetLocInt : RetLoc2Int;
+            rloc = mode64 ? mk_RetLoc_simple(RLPri_Int) :
+                            mk_RetLoc_simple(RLPri_2Int);
          }
          else {
             goto irreducible;
@@ -1681,12 +1772,13 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e)
             break;
       }
 
-      RetLoc rloc = RetLocINVALID;
+      RetLoc rloc = mk_RetLoc_INVALID();
       if (ty == Ity_I32) {
-         rloc = RetLocInt;
+         rloc = mk_RetLoc_simple(RLPri_Int);
       }
       else if (ty == Ity_I64) {
-         rloc = mode64 ? RetLocInt : RetLoc2Int;
+         rloc = mode64 ? mk_RetLoc_simple(RLPri_Int) :
+                         mk_RetLoc_simple(RLPri_2Int);
       }
       else {
          goto irreducible;
@@ -1796,23 +1888,18 @@ static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e)
       /* 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 return types are allowed in future. */
-      if (e->Iex.CCall.retty != Ity_I32 && !mode64)
+      if (e->Iex.CCall.retty != Ity_I32)
          goto irreducible;
 
-      /* What's the retloc? */
-      RetLoc rloc = RetLocINVALID;
-      if (ty == Ity_I32) {
-         rloc = RetLocInt;
-      }
-      else if (ty == Ity_I64) {
-         rloc = mode64 ? RetLocInt : RetLoc2Int;
-      }
-      else {
-         goto irreducible;
-      }
-
       /* Marshal args, do the call, clear stack. */
-      doHelperCall(env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args, rloc);
+      UInt   addToSp = 0;
+      RetLoc rloc    = mk_RetLoc_INVALID();
+      doHelperCall(&addToSp, &rloc, env, NULL/*guard*/, e->Iex.CCall.cee,
+                   e->Iex.CCall.retty, e->Iex.CCall.args );
+
+      vassert(is_sane_RetLoc(rloc));
+      vassert(rloc.pri == RLPri_Int);
+      vassert(addToSp == 0);
       addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
       return r_dst;
    }
@@ -3704,66 +3791,92 @@ static void iselStmt(ISelEnv * env, IRStmt * stmt)
       /* --------- Call to DIRTY helper --------- */
       case Ist_Dirty: {
          IRDirty *d = stmt->Ist.Dirty.details;
-         Bool passBBP = False;
-
-         if (d->nFxState == 0)
-            vassert(!d->needsBBP);
-
-         passBBP = toBool(d->nFxState > 0 && d->needsBBP);
 
          /* 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;
+         /* Throw out any return types we don't know about. */
+         Bool retty_ok = False;
          switch (retty) {
-            case Ity_INVALID: /* function doesn't return anything */
-               rloc = RetLocNone; break;
-            case Ity_I64:
-               rloc = mode64 ? RetLocInt : RetLoc2Int; break;
-            case Ity_I32: case Ity_I16: case Ity_I8:
-               rloc = RetLocInt; break;
+            case Ity_INVALID: /* Function doesn't return anything. */
+            case Ity_V128:
+            case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
+               retty_ok = True; break;
             default:
                break;
          }
-         if (rloc == RetLocINVALID)
+
+         if (!retty_ok)
             break; /* will go to stmt_fail: */
 
-         /* Marshal args, do the call, clear stack. */
-         doHelperCall(env, passBBP, d->guard, d->cee, d->args, rloc);
+         /* 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. */
+         UInt   addToSp = 0;
+         RetLoc rloc    = mk_RetLoc_INVALID();
+         doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args );
+         vassert(is_sane_RetLoc(rloc));
 
          /* Now figure out what to do with the returned value, if any. */
-         if (d->tmp == IRTemp_INVALID)
-            /* No return value.  Nothing to do. */
-            return;
+         switch (retty) {
+            case Ity_INVALID: {
+               /* No return value.  Nothing to do. */
+               vassert(d->tmp == IRTemp_INVALID);
+               vassert(rloc.pri == RLPri_None);
+               vassert(addToSp == 0);
+               return;
+            }
+            case Ity_I32: case Ity_I16: case Ity_I8: {
+               /* The returned value is in $v0.  Park it in the register
+                  associated with tmp. */
+               HReg r_dst = lookupIRTemp(env, d->tmp);
+               addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
+               vassert(rloc.pri == RLPri_Int);
+               vassert(addToSp == 0);
+               return;
+            }
+            case Ity_I64: {
+               if (mode64) {
+                  /* The returned value is in $v0.  Park it in the register
+                     associated with tmp. */
+                  HReg r_dst = lookupIRTemp(env, d->tmp);
+                  addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
+                  vassert(rloc.pri == RLPri_Int);
+                  vassert(addToSp == 0);
+                  return;
+               } else {
+                  HReg rHi = newVRegI(env);
+                  HReg rLo = newVRegI(env);
+                  HReg dstHi, dstLo;
+                  addInstr(env, mk_iMOVds_RR(rLo, hregMIPS_GPR2(mode64)));
+                  addInstr(env, mk_iMOVds_RR(rHi, hregMIPS_GPR3(mode64)));
+                  lookupIRTemp64(&dstHi, &dstLo, env, d->tmp);
+                  addInstr(env, mk_iMOVds_RR(dstHi, rHi));
+                  addInstr(env, mk_iMOVds_RR(dstLo, rLo));
+                  return;
+               }
+            }
+            case Ity_V128: {
+               /* ATC. The code that this produces really
+                  needs to be looked at, to verify correctness.
+                  I don't think this can ever happen though, since the
+                  MIPS front end never produces 128-bit loads/stores. */
+               vassert(0);
+               vassert(rloc.pri == RLPri_V128SpRel);
+               vassert(addToSp >= 16);
+               HReg       dst = lookupIRTemp(env, d->tmp);
+               MIPSAMode* am  = MIPSAMode_IR(rloc.spOff, StackPointer(mode64));
+               addInstr(env, MIPSInstr_Load(mode64 ? 8 : 4, dst, am, mode64));
+               add_to_sp(env, addToSp);
+               return;
 
-         if (retty == Ity_I64 && !mode64) {
-            HReg rHi = newVRegI(env);
-            HReg rLo = newVRegI(env);
-            HReg dstHi, dstLo;
-            addInstr(env, mk_iMOVds_RR(rLo, hregMIPS_GPR2(mode64)));
-            addInstr(env, mk_iMOVds_RR(rHi, hregMIPS_GPR3(mode64)));
-            lookupIRTemp64(&dstHi, &dstLo, env, d->tmp);
-            addInstr(env, mk_iMOVds_RR(dstHi, rHi));
-            addInstr(env, mk_iMOVds_RR(dstLo, rLo));
-            return;
-         }
-         if (retty == Ity_I8 || retty == Ity_I16 || retty == Ity_I32
-             || (retty == Ity_I64 && mode64)) {
-            /* The returned value is in %r2.  Park it in the register
-               associated with tmp. */
-            HReg r_dst = lookupIRTemp(env, d->tmp);
-            addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
-            return;
+            }
+            default:
+               /*NOTREACHED*/
+               vassert(0);
          }
-         break;
       }
 
       /* --------- Load Linked or Store Conditional --------- */
index 28dbac2cc4cf5a657c558610f675b05c02a81c8a..8d3c007e36f1c61e1737d507af4c0d7bbc209162 100644 (file)
@@ -850,7 +850,7 @@ PPCInstr* PPCInstr_Call ( PPCCondCode cond,
    /* Only r3 .. r10 inclusive may be used as arg regs. Hence: */
    mask = (1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9)|(1<<10);
    vassert(0 == (argiregs & ~mask));
-   vassert(rloc != RetLocINVALID);
+   vassert(is_sane_RetLoc(rloc));
    return i;
 }
 PPCInstr* PPCInstr_XDirect ( Addr64 dstGA, PPCAMode* amCIA,
@@ -3913,7 +3913,7 @@ Int emit_PPCInstr ( /*MB_MOD*/Bool* is_profInc,
 
    case Pin_Call: {
       if (i->Pin.Call.cond.test != Pct_ALWAYS
-          && i->Pin.Call.rloc != RetLocNone) {
+          && i->Pin.Call.rloc.pri != RLPri_None) {
          /* The call might not happen (it isn't unconditional) and it
             returns a result.  In this case we will need to generate a
             control flow diamond to put 0x555..555 in the return
index a458ea0152cfe96bfd7ecce43b27dd545c094173..54048efdf510e409ca6efbc5e6238982ae5d93d5 100644 (file)
@@ -490,7 +490,7 @@ static PPCInstr* mk_iMOVds_RR ( HReg r_dst, HReg r_src )
 static void add_to_sp ( ISelEnv* env, UInt n )
 {
    HReg sp = StackFramePtr(env->mode64);
-   vassert(n < 256 && (n%16) == 0);
+   vassert(n <= 1024 && (n%16) == 0);
    addInstr(env, PPCInstr_Alu( Palu_ADD, sp, sp,
                                PPCRH_Imm(True,toUShort(n)) ));
 }
@@ -498,7 +498,7 @@ static void add_to_sp ( ISelEnv* env, UInt n )
 static void sub_from_sp ( ISelEnv* env, UInt n )
 {
    HReg sp = StackFramePtr(env->mode64);
-   vassert(n < 256 && (n%16) == 0);
+   vassert(n <= 1024 && (n%16) == 0);
    addInstr(env, PPCInstr_Alu( Palu_SUB, sp, sp,
                                PPCRH_Imm(True,toUShort(n)) ));
 }
@@ -673,15 +673,19 @@ Bool mightRequireFixedRegs ( IRExpr* e )
 }
 
 
-/* Do a complete function call.  guard is a Ity_Bit expression
+/* Do a complete function call.  |guard| is a Ity_Bit expression
    indicating whether or not the call happens.  If guard==NULL, the
-   call is unconditional. */
+   call is unconditional.  |retloc| is set to indicate where the
+   return value is after the call.  The caller (of this fn) must
+   generate code to add |stackAdjustAfterCall| to the stack pointer
+   after the call is done. */
 
 static
-void doHelperCall ( ISelEnv* env, 
-                    Bool passBBP, 
-                    IRExpr* guard, IRCallee* cee, IRExpr** args,
-                    RetLoc rloc )
+void doHelperCall ( /*OUT*/UInt*   stackAdjustAfterCall,
+                    /*OUT*/RetLoc* retloc,
+                    ISelEnv* env,
+                    IRExpr* guard,
+                    IRCallee* cee, IRType retTy, IRExpr** args )
 {
    PPCCondCode cc;
    HReg        argregs[PPC_N_REGPARMS];
@@ -689,25 +693,43 @@ void doHelperCall ( ISelEnv* env,
    Bool        go_fast;
    Int         n_args, i, argreg;
    UInt        argiregs;
-   ULong       target;
    Bool        mode64 = env->mode64;
 
-   /* Do we need to force use of an odd-even reg pair for 64-bit
-      args? */
+   /* Set default returns.  We'll update them later if needed. */
+   *stackAdjustAfterCall = 0;
+   *retloc               = mk_RetLoc_INVALID();
+
+   /* These are used for cross-checking that IR-level constraints on
+      the use of IRExprP__VECRET and IRExprP__BBPTR are observed. */
+   UInt nVECRETs = 0;
+   UInt nBBPTRs  = 0;
+
+   /* Do we need to force use of an odd-even reg pair for 64-bit args?
+      JRS 31-07-2013: is this still relevant, now that we are not
+      generating code for 32-bit AIX ? */
    Bool regalign_int64s
       = (!mode64) && env->vbi->host_ppc32_regalign_int64_args;
 
    /* Marshal args for a call and do the call.
 
-      If passBBP is True, %rbp (the baseblock pointer) is to be passed
-      as the first arg.
-
       This function only deals with a tiny set of possibilities, which
       cover all helpers in practice.  The restrictions are that only
       arguments in registers are supported, hence only PPC_N_REGPARMS x
       (mode32:32 | mode64:64) integer bits in total can be passed.
       In fact the only supported arg type is (mode32:I32 | mode64:I64).
 
+      The return type can be I{64,32,16,8} or V{128,256}.  In the
+      latter two cases, it is expected that |args| will contain the
+      special value IRExprP__VECRET, in which case this routine
+      generates code to allocate space on the stack for the vector
+      return value.  Since we are not passing any scalars on the
+      stack, it is enough to preallocate the return space before
+      marshalling any arguments, in this case.
+
+      |args| may also contain IRExprP__BBPTR, in which case the value
+      in the guest state pointer register is passed as the
+      corresponding argument.
+
       Generating code which is both efficient and correct when
       parameters are to be passed in registers is difficult, for the
       reasons elaborated in detail in comments attached to
@@ -751,10 +773,14 @@ void doHelperCall ( ISelEnv* env,
    for (i = 0; args[i]; i++)
       n_args++;
 
-   if (PPC_N_REGPARMS < n_args + (passBBP ? 1 : 0)) {
+   if (n_args > PPC_N_REGPARMS) {
       vpanic("doHelperCall(PPC): cannot currently handle > 8 args");
       // PPC_N_REGPARMS
    }
+
+   /* This is kind of stupid .. the arrays are sized as PPC_N_REGPARMS
+      but we then assume that that value is 8. */
+   vassert(PPC_N_REGPARMS == 8);
    
    argregs[0] = hregPPC_GPR3(mode64);
    argregs[1] = hregPPC_GPR4(mode64);
@@ -776,7 +802,13 @@ void doHelperCall ( ISelEnv* env,
 
    go_fast = True;
 
-   if (guard) {
+   /* We'll need space on the stack for the return value.  Avoid
+      possible complications with nested calls by using the slow
+      scheme. */
+   if (retTy == Ity_V128 || retTy == Ity_V256)
+      go_fast = False;
+
+   if (go_fast && guard) {
       if (guard->tag == Iex_Const 
           && guard->Iex.Const.con->tag == Ico_U1
           && guard->Iex.Const.con->Ico.U1 == True) {
@@ -789,7 +821,17 @@ void doHelperCall ( ISelEnv* env,
 
    if (go_fast) {
       for (i = 0; i < n_args; i++) {
-         if (mightRequireFixedRegs(args[i])) {
+         IRExpr* arg = args[i];
+         if (UNLIKELY(arg == IRExprP__BBPTR)) {
+            /* that's OK */
+         } 
+         else if (UNLIKELY(arg == IRExprP__VECRET)) {
+            /* This implies ill-formed IR, since if the IR was
+               well-formed, the return-type test above would have
+               filtered it out. */
+            vpanic("doHelperCall(PPC): invalid IR");
+         }
+         else if (mightRequireFixedRegs(arg)) {
             go_fast = False;
             break;
          }
@@ -803,41 +845,45 @@ void doHelperCall ( ISelEnv* env,
 
       /* FAST SCHEME */
       argreg = 0;
-      if (passBBP) {
-         argiregs |= (1 << (argreg+3));
-         addInstr(env, mk_iMOVds_RR( argregs[argreg],
-                                     GuestStatePtr(mode64) ));
-         argreg++;
-      }
 
       for (i = 0; i < n_args; i++) {
+         IRExpr* arg = args[i];
          vassert(argreg < PPC_N_REGPARMS);
-         vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32 ||
-                 typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
-         if (!mode64) {
-            if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) { 
-               argiregs |= (1 << (argreg+3));
-               addInstr(env,
-                        mk_iMOVds_RR( argregs[argreg],
-                                      iselWordExpr_R(env, args[i]) ));
-            } else { // Ity_I64
-               HReg rHi, rLo;
-               if (regalign_int64s && (argreg%2) == 1) 
-                              // ppc32 ELF abi spec for passing LONG_LONG
-                  argreg++;   // XXX: odd argreg => even rN
-               vassert(argreg < PPC_N_REGPARMS-1);
-               iselInt64Expr(&rHi,&rLo, env, args[i]);
-               argiregs |= (1 << (argreg+3));
-               addInstr(env, mk_iMOVds_RR( argregs[argreg++], rHi ));
-               argiregs |= (1 << (argreg+3));
-               addInstr(env, mk_iMOVds_RR( argregs[argreg], rLo));
-            }
-         } else { // mode64
+
+         if (arg == IRExprP__BBPTR) {
             argiregs |= (1 << (argreg+3));
             addInstr(env, mk_iMOVds_RR( argregs[argreg],
-                                        iselWordExpr_R(env, args[i]) ));
-         }
-         argreg++;
+                                        GuestStatePtr(mode64) ));
+            argreg++;
+         } else {
+            vassert(arg != IRExprP__VECRET);
+            IRType ty = typeOfIRExpr(env->type_env, arg);
+            vassert(ty == Ity_I32 || ty == Ity_I64);
+            if (!mode64) {
+               if (ty == Ity_I32) { 
+                  argiregs |= (1 << (argreg+3));
+                  addInstr(env,
+                           mk_iMOVds_RR( argregs[argreg],
+                                         iselWordExpr_R(env, arg) ));
+               } else { // Ity_I64 in 32-bit mode
+                  HReg rHi, rLo;
+                  if (regalign_int64s && (argreg%2) == 1) 
+                                 // ppc32 ELF abi spec for passing LONG_LONG
+                     argreg++;   // XXX: odd argreg => even rN
+                  vassert(argreg < PPC_N_REGPARMS-1);
+                  iselInt64Expr(&rHi,&rLo, env, arg);
+                  argiregs |= (1 << (argreg+3));
+                  addInstr(env, mk_iMOVds_RR( argregs[argreg++], rHi ));
+                  argiregs |= (1 << (argreg+3));
+                  addInstr(env, mk_iMOVds_RR( argregs[argreg], rLo));
+               }
+            } else { // mode64
+               argiregs |= (1 << (argreg+3));
+               addInstr(env, mk_iMOVds_RR( argregs[argreg],
+                                           iselWordExpr_R(env, arg) ));
+            }
+            argreg++;
+         } /* if (arg == IRExprP__BBPR) */
       }
 
       /* Fast scheme only applies for unconditional calls.  Hence: */
@@ -848,34 +894,66 @@ void doHelperCall ( ISelEnv* env,
       /* SLOW SCHEME; move via temporaries */
       argreg = 0;
 
-      if (passBBP) {
-         /* This is pretty stupid; better to move directly to r3
-            after the rest of the args are done. */
-         tmpregs[argreg] = newVRegI(env);
-         addInstr(env, mk_iMOVds_RR( tmpregs[argreg],
-                                     GuestStatePtr(mode64) ));
-         argreg++;
-      }
-
+      /* If we have a vector return type, allocate a place for it on
+         the stack and record its address.  Rather than figure out the
+         complexities of PPC{32,64} ELF ABI stack frame layout, simply
+         drop the SP by 1024 and allocate the return point in the
+         middle.  I think this should comfortably clear any ABI
+         mandated register save areas.  Note that it doesn't maintain
+         the backchain as it should, since we're not doing st{d,w}u to
+         adjust the SP, but .. that doesn't seem to be a big deal.
+         Since we're not expecting to have to unwind out of here. */
+      HReg r_vecRetAddr = INVALID_HREG;
+      if (retTy == Ity_V128) {
+         r_vecRetAddr = newVRegI(env);
+         sub_from_sp(env, 512);
+         addInstr(env, mk_iMOVds_RR( r_vecRetAddr, StackFramePtr(mode64) ));
+         sub_from_sp(env, 512);
+      }
+      else if (retTy == Ity_V256) {
+         vassert(0); //ATC
+         r_vecRetAddr = newVRegI(env);
+         sub_from_sp(env, 512);
+         addInstr(env, mk_iMOVds_RR( r_vecRetAddr, StackFramePtr(mode64) ));
+         sub_from_sp(env, 512);
+      }
+
+      vassert(n_args >= 0 && n_args <= 8);
       for (i = 0; i < n_args; i++) {
+         IRExpr* arg = args[i];
          vassert(argreg < PPC_N_REGPARMS);
-         vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32 ||
-                 typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
-         if (!mode64) {
-            if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) { 
-               tmpregs[argreg] = iselWordExpr_R(env, args[i]);
-            } else { // Ity_I64
-               HReg rHi, rLo;
-               if (regalign_int64s && (argreg%2) == 1)
-                             // ppc32 ELF abi spec for passing LONG_LONG
-                  argreg++;  // XXX: odd argreg => even rN
-               vassert(argreg < PPC_N_REGPARMS-1);
-               iselInt64Expr(&rHi,&rLo, env, args[i]);
-               tmpregs[argreg++] = rHi;
-               tmpregs[argreg]   = rLo;
+         if (UNLIKELY(arg == IRExprP__BBPTR)) {
+            tmpregs[argreg] = newVRegI(env);
+            addInstr(env, mk_iMOVds_RR( tmpregs[argreg],
+                                        GuestStatePtr(mode64) ));
+            nBBPTRs++;
+         }
+         else if (UNLIKELY(arg == IRExprP__VECRET)) {
+            /* We stashed the address of the return slot earlier, so just
+               retrieve it now. */
+            vassert(!hregIsInvalid(r_vecRetAddr));
+            tmpregs[i] = r_vecRetAddr;
+            nVECRETs++;
+         }
+         else {
+            IRType ty = typeOfIRExpr(env->type_env, arg);
+            vassert(ty == Ity_I32 || ty == Ity_I64);
+            if (!mode64) {
+               if (ty == Ity_I32) { 
+                  tmpregs[argreg] = iselWordExpr_R(env, arg);
+               } else { // Ity_I64 in 32-bit mode
+                  HReg rHi, rLo;
+                  if (regalign_int64s && (argreg%2) == 1)
+                                // ppc32 ELF abi spec for passing LONG_LONG
+                     argreg++;  // XXX: odd argreg => even rN
+                  vassert(argreg < PPC_N_REGPARMS-1);
+                  iselInt64Expr(&rHi,&rLo, env, arg);
+                  tmpregs[argreg++] = rHi;
+                  tmpregs[argreg]   = rLo;
+               }
+            } else { // mode64
+               tmpregs[argreg] = iselWordExpr_R(env, arg);
             }
-         } else { // mode64
-            tmpregs[argreg] = iselWordExpr_R(env, args[i]);
          }
          argreg++;
       }
@@ -907,11 +985,53 @@ void doHelperCall ( ISelEnv* env,
 
    }
 
-   target = mode64 ? Ptr_to_ULong(cee->addr) :
-                     toUInt(Ptr_to_ULong(cee->addr));
+   /* Do final checks, set the return values, and generate the call
+      instruction proper. */
+   if (retTy == Ity_V128 || retTy == Ity_V256) {
+      vassert(nVECRETs == 1);
+   } else {
+      vassert(nVECRETs == 0);
+   }
 
-   /* Finally, the call itself. */
-   addInstr(env, PPCInstr_Call( cc, (Addr64)target, argiregs, rloc ));
+   vassert(nBBPTRs == 0 || nBBPTRs == 1);
+
+   vassert(*stackAdjustAfterCall == 0);
+   vassert(is_RetLoc_INVALID(*retloc));
+   switch (retTy) {
+      case Ity_INVALID:
+         /* Function doesn't return a value. */
+         *retloc = mk_RetLoc_simple(RLPri_None);
+         break;
+      case Ity_I64:
+         *retloc = mk_RetLoc_simple(mode64 ? RLPri_Int : RLPri_2Int);
+         break;
+      case Ity_I32: case Ity_I16: case Ity_I8:
+         *retloc = mk_RetLoc_simple(RLPri_Int);
+         break;
+      case Ity_V128:
+         /* Result is 512 bytes up the stack, and after it has been
+            retrieved, adjust SP upwards by 1024. */
+         *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 512);
+         *stackAdjustAfterCall = 1024;
+         break;
+      case Ity_V256:
+         vassert(0); // ATC
+         /* Ditto */
+         *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 512);
+         *stackAdjustAfterCall = 1024;
+         break;
+      default:
+         /* IR can denote other possible return types, but we don't
+            handle those here. */
+         vassert(0);
+   }
+
+   /* Finally, generate the call itself.  This needs the *retloc value
+      set in the switch above, which is why it's at the end. */
+
+   ULong target = mode64 ? Ptr_to_ULong(cee->addr)
+                         : toUInt(Ptr_to_ULong(cee->addr));
+   addInstr(env, PPCInstr_Call( cc, (Addr64)target, argiregs, *retloc ));
 }
 
 
@@ -2079,7 +2199,7 @@ static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e )
 
          fdescr = (HWord*)h_calc_BCDtoDPB;
          addInstr(env, PPCInstr_Call( cc, (Addr64)(fdescr[0]),
-                                      argiregs, RetLocInt) );
+                                      argiregs, mk_RetLoc_simple(RLPri_Int)) );
 
          addInstr(env, mk_iMOVds_RR(r_dst, argregs[0]));
          return r_dst;
@@ -2108,7 +2228,7 @@ static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e )
 
          fdescr = (HWord*)h_calc_DPBtoBCD;
          addInstr(env, PPCInstr_Call( cc, (Addr64)(fdescr[0]),
-                                      argiregs, RetLocInt ) );
+                                      argiregs, mk_RetLoc_simple(RLPri_Int) ) );
 
          addInstr(env, mk_iMOVds_RR(r_dst, argregs[0]));
          return r_dst;
@@ -2196,14 +2316,18 @@ static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e )
       vassert(ty == Ity_I32);
 
       /* 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 return types are allowed in future. */
+         args, and 32 bits for return type. */
       if (e->Iex.CCall.retty != Ity_I32)
          goto irreducible;
-      
+
       /* Marshal args, do the call, clear stack. */
-      doHelperCall( env, False, NULL,
-                    e->Iex.CCall.cee, e->Iex.CCall.args, RetLocInt );
+      UInt   addToSp = 0;
+      RetLoc rloc    = mk_RetLoc_INVALID();
+      doHelperCall( &addToSp, &rloc, env, NULL/*guard*/,
+                    e->Iex.CCall.cee, e->Iex.CCall.retty, e->Iex.CCall.args );
+      vassert(is_sane_RetLoc(rloc));
+      vassert(rloc.pri == RLPri_Int);
+      vassert(addToSp == 0);
 
       /* GPR3 now holds the destination address from Pin_Goto */
       addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
@@ -3449,7 +3573,8 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
          target = toUInt( Ptr_to_ULong(h_calc_BCDtoDPB ) );
 
          addInstr( env, PPCInstr_Call( cc, (Addr64)target,
-                                       argiregs, RetLoc2Int ) );
+                                       argiregs,
+                                       mk_RetLoc_simple(RLPri_2Int) ) );
          addInstr( env, mk_iMOVds_RR( tHi, argregs[argreg-1] ) );
          addInstr( env, mk_iMOVds_RR( tLo, argregs[argreg] ) );
 
@@ -3488,8 +3613,8 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
 
          target = toUInt( Ptr_to_ULong( h_calc_DPBtoBCD ) );
 
-         addInstr(env, PPCInstr_Call( cc, (Addr64)target,
-                                      argiregs, RetLoc2Int ) );
+         addInstr(env, PPCInstr_Call( cc, (Addr64)target, argiregs,
+                                      mk_RetLoc_simple(RLPri_2Int) ) );
          addInstr(env, mk_iMOVds_RR(tHi, argregs[argreg-1]));
          addInstr(env, mk_iMOVds_RR(tLo, argregs[argreg]));
 
@@ -5331,64 +5456,99 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
    /* --------- Call to DIRTY helper --------- */
    case Ist_Dirty: {
       IRDirty* d = stmt->Ist.Dirty.details;
-      Bool     passBBP = False;
-
-      if (d->nFxState == 0)
-         vassert(!d->needsBBP);
-      passBBP = toBool(d->nFxState > 0 && d->needsBBP);
 
       /* 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 = mode64 ? RetLocInt : RetLoc2Int; break;
-      case Ity_I32: case Ity_I16: case Ity_I8:
-         rloc = RetLocInt; break;
-      default:
-         break;
+      /* Throw out any return types we don't know about. */
+      Bool retty_ok = False;
+      if (mode64) {
+         switch (retty) {
+            case Ity_INVALID: /* function doesn't return anything */
+            case Ity_V128:
+            case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
+               retty_ok = True; break;
+            default:
+               break;
+         }
+      } else {
+         switch (retty) {
+            case Ity_INVALID: /* function doesn't return anything */
+            case Ity_V128:
+            case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
+               retty_ok = True; break;
+            default:
+               break;
+         }
       }
-      if (rloc == RetLocINVALID)
+      if (!retty_ok)
          break; /* will go to stmt_fail: */
 
-      /* Marshal args, do the call, clear stack. */
-      doHelperCall( env, passBBP, d->guard, d->cee, d->args, rloc );
+      /* 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. */
+      UInt   addToSp = 0;
+      RetLoc rloc    = mk_RetLoc_INVALID();
+      doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args );
+      vassert(is_sane_RetLoc(rloc));
 
       /* Now figure out what to do with the returned value, if any. */
-      if (d->tmp == IRTemp_INVALID)
-         /* No return value.  Nothing to do. */
-         return;
-
-      if (!mode64 && retty == Ity_I64) {
-         HReg r_dstHi, r_dstLo;
-         /* The returned value is in %r3:%r4.  Park it in the
-            register-pair associated with tmp. */
-         lookupIRTempPair( &r_dstHi, &r_dstLo, env, d->tmp);
-         addInstr(env, mk_iMOVds_RR(r_dstHi, hregPPC_GPR3(mode64)));
-         addInstr(env, mk_iMOVds_RR(r_dstLo, hregPPC_GPR4(mode64)));
-         vassert(rloc == RetLoc2Int);
-         return;
-      }
-      if (retty == Ity_I8  || retty == Ity_I16 ||
-          retty == Ity_I32 || ((retty == Ity_I64) && mode64)) {
-         /* The returned value is in %r3.  Park it in the register
-            associated with tmp. */
-         HReg r_dst = lookupIRTemp(env, d->tmp);
-         addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
-         vassert(rloc == RetLocInt);
-         return;
+      switch (retty) {
+         case Ity_INVALID: {
+            /* No return value.  Nothing to do. */
+            vassert(d->tmp == IRTemp_INVALID);
+            vassert(rloc.pri == RLPri_None);
+            vassert(addToSp == 0);
+            return;
+         }
+         case Ity_I32: case Ity_I16: case Ity_I8: {
+            /* The returned value is in %r3.  Park it in the register
+               associated with tmp. */
+            HReg r_dst = lookupIRTemp(env, d->tmp);
+            addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
+            vassert(rloc.pri == RLPri_Int);
+            vassert(addToSp == 0);
+            return;
+         }
+         case Ity_I64:
+            if (mode64) {
+               /* The returned value is in %r3.  Park it in the register
+                  associated with tmp. */
+               HReg r_dst = lookupIRTemp(env, d->tmp);
+               addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
+               vassert(rloc.pri == RLPri_Int);
+               vassert(addToSp == 0);
+            } else {
+               /* The returned value is in %r3:%r4.  Park it in the
+                  register-pair associated with tmp. */
+               HReg r_dstHi = INVALID_HREG;
+               HReg r_dstLo = INVALID_HREG;
+               lookupIRTempPair( &r_dstHi, &r_dstLo, env, d->tmp);
+               addInstr(env, mk_iMOVds_RR(r_dstHi, hregPPC_GPR3(mode64)));
+               addInstr(env, mk_iMOVds_RR(r_dstLo, hregPPC_GPR4(mode64)));
+               vassert(rloc.pri == RLPri_2Int);
+               vassert(addToSp == 0);
+            }
+            return;
+         case Ity_V128: {
+            /* The returned value is on the stack, and *retloc tells
+               us where.  Fish it off the stack and then move the
+               stack pointer upwards to clear it, as directed by
+               doHelperCall. */
+            vassert(rloc.pri == RLPri_V128SpRel);
+            vassert(addToSp >= 16);
+            HReg      dst = lookupIRTemp(env, d->tmp);
+            PPCAMode* am  = PPCAMode_IR(rloc.spOff, StackFramePtr(mode64));
+            addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, dst, am ));
+            add_to_sp(env, addToSp);
+            return;
+         }
+         default:
+            /*NOTREACHED*/
+            vassert(0);
       }
-      break;
    }
 
    /* --------- MEM FENCE --------- */
index 7a3eab7d500ad905d9690fd2de0e3d28a8a747e8..44faad65b5e31522f5e01c7b903d338bbee307a1 100644 (file)
@@ -646,8 +646,6 @@ s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn)
       for (i = 1; i <= 5; ++i) {
          addHRegUse(u, HRmWrite, mkHReg(i, HRcInt64, False));
       }
-      if (! hregIsInvalid(insn->variant.helper_call.dst))
-         addHRegUse(u, HRmWrite, insn->variant.helper_call.dst);
 
       /* Ditto for floating point registers. f0 - f7 are volatile */
       for (i = 0; i <= 7; ++i) {
@@ -656,7 +654,7 @@ s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn)
 
       /* The registers that are used for passing arguments will be read.
          Not all of them may, but in general we need to assume that. */
-      for (i = 0; i < insn->variant.helper_call.num_args; ++i) {
+      for (i = 0; i < insn->variant.helper_call.details->num_args; ++i) {
          addHRegUse(u, HRmRead, mkHReg(s390_gprno_from_arg_index(i),
                                        HRcInt64, False));
       }
@@ -969,8 +967,6 @@ s390_insn_map_regs(HRegRemap *m, s390_insn *insn)
          As for the arguments of the helper call -- they will be loaded into
          non-virtual registers. Again, we don't need to do anything for those
          here. */
-      if (! hregIsInvalid(insn->variant.helper_call.dst)) 
-         insn->variant.helper_call.dst = lookupHRegRemap(m, insn->variant.helper_call.dst);
       break;
 
    case S390_INSN_BFP_TRIOP:
@@ -5652,17 +5648,22 @@ s390_insn_compare(UChar size, HReg src1, s390_opnd_RMI src2,
 
 s390_insn *
 s390_insn_helper_call(s390_cc_t cond, Addr64 target, UInt num_args,
-                      const HChar *name, HReg dst)
+                      const HChar *name, RetLoc rloc)
 {
    s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
+   s390_helper_call *helper_call = LibVEX_Alloc(sizeof(s390_helper_call));
 
    insn->tag  = S390_INSN_HELPER_CALL;
    insn->size = 0;  /* does not matter */
-   insn->variant.helper_call.cond = cond;
-   insn->variant.helper_call.target = target;
-   insn->variant.helper_call.num_args = num_args;
-   insn->variant.helper_call.name = name;
-   insn->variant.helper_call.dst = dst;
+   insn->variant.helper_call.details = helper_call;
+
+   helper_call->cond = cond;
+   helper_call->target = target;
+   helper_call->num_args = num_args;
+   helper_call->name = name;
+   helper_call->rloc = rloc;
+
+   vassert(is_sane_RetLoc(rloc));
 
    return insn;
 }
@@ -6736,20 +6737,12 @@ s390_insn_as_string(const s390_insn *insn)
       break;
 
    case S390_INSN_HELPER_CALL: {
-      if (! hregIsInvalid(insn->variant.helper_call.dst)) {
-         s390_sprintf(buf, "%M if (%C) %R = %s{%I}(%L)", "v-call",
-                      insn->variant.helper_call.cond,
-                      insn->variant.helper_call.dst,
-                      insn->variant.helper_call.name,
-                      insn->variant.helper_call.target,
-                      insn->variant.helper_call.num_args);
-      } else {
-         s390_sprintf(buf, "%M if (%C) %s{%I}(%L)", "v-call",
-                      insn->variant.helper_call.cond,
-                      insn->variant.helper_call.name,
-                      insn->variant.helper_call.target,
-                      insn->variant.helper_call.num_args);
-      }
+      s390_helper_call *helper_call = insn->variant.helper_call.details;
+      s390_sprintf(buf, "%M if (%C) %s{%I}(%L)", "v-call",
+                   helper_call->cond,
+                   helper_call->name,
+                   helper_call->target,
+                   helper_call->num_args);
       return buf;   /* avoid printing "size = ..." which is meaningless */
    }
 
@@ -8732,12 +8725,13 @@ s390_insn_helper_call_emit(UChar *buf, const s390_insn *insn)
    ULong target;
    UChar *ptmp = buf;
    UChar *bufIN = buf;
+   s390_helper_call *helper_call = insn->variant.helper_call.details;
 
-   cond = insn->variant.helper_call.cond;
-   target = insn->variant.helper_call.target;
+   cond = helper_call->cond;
+   target = helper_call->target;
 
    if (cond != S390_CC_ALWAYS
-       && ! hregIsInvalid(insn->variant.helper_call.dst)) {
+       && helper_call->rloc.pri != RLPri_None) {
       /* The call might not happen (it isn't unconditional) and it
          returns a result.  In this case we will need to generate a
          control flow diamond to put 0x555..555 in the return
@@ -8774,12 +8768,6 @@ s390_insn_helper_call_emit(UChar *buf, const s390_insn *insn)
 
    buf = s390_emit_BASR(buf, S390_REGNO_LINK_REGISTER, 1);      // call helper
 
-   /* Move the return value to the destination register */
-   if (! hregIsInvalid(insn->variant.helper_call.dst)) {
-      buf = s390_emit_LGR(buf, hregNumber(insn->variant.helper_call.dst),
-                          S390_REGNO_RETURN_VALUE);
-   }
-
    buf = s390_emit_LFPC(buf, S390_REGNO_STACK_POINTER,          // restore FPC
                         S390_OFFSET_SAVED_FPC_C);
 
index 3fca721fcfe4542cbf4ccd0739567624f10acf06..9c2571e6e0af069557f5799a99a75f6a18f8d7c5 100644 (file)
@@ -354,6 +354,20 @@ typedef struct {
    HReg         r1;     /* clobbered register GPR #1 */
 } s390_fp_convert;
 
+/* Pseudo-insn for representing a helper call.
+   TARGET is the absolute address of the helper function
+   NUM_ARGS says how many arguments are being passed.
+   All arguments have integer type and are being passed according to ABI,
+   i.e. in registers r2, r3, r4, r5, and r6, with argument #0 being
+   passed in r2 and so forth. */
+typedef struct {
+   s390_cc_t    cond     : 16;
+   UInt         num_args : 16;
+   RetLoc       rloc;     /* where the return value will be */
+   Addr64       target;
+   const HChar *name;      /* callee's name (for debugging) */
+} s390_helper_call;
+
 typedef struct {
    s390_insn_tag tag;
    /* Usually, this is the size of the result of an operation.
@@ -440,18 +454,8 @@ typedef struct {
       struct {
          s390_cdas *details;
       } cdas;
-      /* Pseudo-insn for representing a helper call.
-         TARGET is the absolute address of the helper function
-         NUM_ARGS says how many arguments are being passed.
-         All arguments have integer type and are being passed according to ABI,
-         i.e. in registers r2, r3, r4, r5, and r6, with argument #0 being
-         passed in r2 and so forth. */
-      struct {
-         s390_cc_t    cond     : 16;
-         UInt         num_args : 16;
-         HReg         dst;   /* if not INVALID_HREG, put return value here */
-         Addr64       target;
-         const HChar *name;      /* callee's name (for debugging) */
+      struct {
+         s390_helper_call *details;
       } helper_call;
 
       /* Floating point instructions (including conversion to/from floating
@@ -642,7 +646,7 @@ s390_insn *s390_insn_test(UChar size, s390_opnd_RMI src);
 s390_insn *s390_insn_compare(UChar size, HReg dst, s390_opnd_RMI opnd,
                              Bool signed_comparison);
 s390_insn *s390_insn_helper_call(s390_cc_t cond, Addr64 target, UInt num_args,
-                                 const HChar *name, HReg dst);
+                                 const HChar *name, RetLoc rloc);
 s390_insn *s390_insn_bfp_triop(UChar size, s390_bfp_triop_t, HReg dst,
                                HReg op2, HReg op3);
 s390_insn *s390_insn_bfp_binop(UChar size, s390_bfp_binop_t, HReg dst,
index d84125d8ab17d4476bfc3658085d59373140ab77..e8c260e23bd0ee8c213fee9851445f29a9c510af 100644 (file)
@@ -470,19 +470,42 @@ get_const_value_as_ulong(const IRConst *con)
    of the register allocator to throw out those reg-to-reg moves.
 */
 static void
-doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard,
-             IRCallee *callee, IRExpr **args, HReg dst)
+doHelperCall(/*OUT*/UInt *stackAdjustAfterCall,
+             /*OUT*/RetLoc *retloc,
+             ISelEnv *env, IRExpr *guard,
+             IRCallee *callee, IRType retTy, IRExpr **args)
 {
    UInt n_args, i, argreg, size;
    ULong target;
    HReg tmpregs[S390_NUM_GPRPARMS];
    s390_cc_t cc;
 
+   /* Set default returns.  We'll update them later if needed. */
+   *stackAdjustAfterCall = 0;
+   *retloc               = mk_RetLoc_INVALID();
+
+   /* The return type can be I{64,32,16,8} or V{128,256}.  In the
+      latter two cases, it is expected that |args| will contain the
+      special value IRExprP__VECRET, in which case this routine
+      generates code to allocate space on the stack for the vector
+      return value.  Since we are not passing any scalars on the
+      stack, it is enough to preallocate the return space before
+      marshalling any arguments, in this case.
+
+      |args| may also contain IRExprP__BBPTR, in which case the value
+      in the guest state pointer register is passed as the
+      corresponding argument.
+
+      These are used for cross-checking that IR-level constraints on
+      the use of IRExprP__VECRET and IRExprP__BBPTR are observed. */
+   UInt nVECRETs = 0;
+   UInt nBBPTRs  = 0;
+
    n_args = 0;
    for (i = 0; args[i]; i++)
       ++n_args;
 
-   if (n_args > (S390_NUM_GPRPARMS - (passBBP ? 1 : 0))) {
+   if (n_args > S390_NUM_GPRPARMS) {
       vpanic("doHelperCall: too many arguments");
    }
 
@@ -493,31 +516,64 @@ doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard,
    */
    Int arg_errors = 0;
    for (i = 0; i < n_args; ++i) {
-      IRType type = typeOfIRExpr(env->type_env, args[i]);
-      if (type != Ity_I64) {
-         ++arg_errors;
-         vex_printf("calling %s: argument #%d has type ", callee->name, i);
-         ppIRType(type);
-         vex_printf("; Ity_I64 is required\n");
+      if (UNLIKELY(args[i] == IRExprP__VECRET)) {
+         nVECRETs++;
+      } else if (UNLIKELY(args[i] == IRExprP__BBPTR)) {
+         nBBPTRs++;
+      } else {
+         IRType type = typeOfIRExpr(env->type_env, args[i]);
+         if (type != Ity_I64) {
+            ++arg_errors;
+            vex_printf("calling %s: argument #%d has type ", callee->name, i);
+            ppIRType(type);
+            vex_printf("; Ity_I64 is required\n");
+         }
       }
    }
 
    if (arg_errors)
       vpanic("cannot continue due to errors in argument passing");
 
-   argreg = 0;
+   /* If this fails, the IR is ill-formed */
+   vassert(nBBPTRs == 0 || nBBPTRs == 1);
+
+   /* If we have a VECRET, allocate space on the stack for the return
+      value, and record the stack pointer after that. */
+   HReg r_vecRetAddr = INVALID_HREG;
+   if (nVECRETs == 1) {
+      /* we do not handle vector types yet */
+      vassert(0);
+      HReg sp = make_gpr(S390_REGNO_STACK_POINTER);
+      vassert(retTy == Ity_V128 || retTy == Ity_V256);
+      vassert(retTy != Ity_V256); // we don't handle that yet (if ever)
+      r_vecRetAddr = newVRegI(env);
+      addInstr(env, s390_insn_alu(4, S390_ALU_SUB, sp, s390_opnd_imm(16)));
+      addInstr(env, s390_insn_move(sizeof(ULong), r_vecRetAddr, sp));
 
-   /* If we need the guest state pointer put it in a temporary arg reg */
-   if (passBBP) {
-      tmpregs[argreg] = newVRegI(env);
-      addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
-                                   s390_hreg_guest_state_pointer()));
-      argreg++;
+   } else {
+      // If either of these fail, the IR is ill-formed
+      vassert(retTy != Ity_V128 && retTy != Ity_V256);
+      vassert(nVECRETs == 0);
    }
 
+   argreg = 0;
+
    /* Compute the function arguments into a temporary register each */
    for (i = 0; i < n_args; i++) {
-      tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
+      IRExpr *arg = args[i];
+      if(UNLIKELY(arg == IRExprP__VECRET)) {
+         /* we do not handle vector types yet */
+         vassert(0);
+         addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
+                                      r_vecRetAddr));
+      } else if (UNLIKELY(arg == IRExprP__BBPTR)) {
+         /* If we need the guest state pointer put it in a temporary arg reg */
+         tmpregs[argreg] = newVRegI(env);
+         addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
+                                      s390_hreg_guest_state_pointer()));
+      } else {
+         tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
+      }
       argreg++;
    }
 
@@ -545,9 +601,39 @@ doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard,
 
    target = Ptr_to_ULong(callee->addr);
 
+   /* Do final checks, set the return values, and generate the call
+      instruction proper. */
+   vassert(*stackAdjustAfterCall == 0);
+   vassert(is_RetLoc_INVALID(*retloc));
+   switch (retTy) {
+   case Ity_INVALID:
+      /* Function doesn't return a value. */
+      *retloc = mk_RetLoc_simple(RLPri_None);
+      break;
+   case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
+      *retloc = mk_RetLoc_simple(RLPri_Int);
+      break;
+   case Ity_V128:
+      /* we do not handle vector types yet */
+      vassert(0);
+      *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 0);
+      *stackAdjustAfterCall = 16;
+      break;
+   case Ity_V256:
+      /* we do not handle vector types yet */
+      vassert(0);
+      *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 0);
+      *stackAdjustAfterCall = 32;
+      break;
+   default:
+      /* IR can denote other possible return types, but we don't
+         handle those here. */
+      vassert(0);
+   }
+
    /* Finally, the call itself. */
    addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
-                                       callee->name, dst));
+                                       callee->name, *retloc));
 }
 
 
@@ -1727,9 +1813,17 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
       /* --------- CCALL --------- */
    case Iex_CCall: {
       HReg dst = newVRegI(env);
+      HReg ret = make_gpr(S390_REGNO_RETURN_VALUE);
+      UInt   addToSp = 0;
+      RetLoc rloc    = mk_RetLoc_INVALID();
+
+      doHelperCall(&addToSp, &rloc, env, NULL, expr->Iex.CCall.cee,
+                   expr->Iex.CCall.retty, expr->Iex.CCall.args);
+      vassert(is_sane_RetLoc(rloc));
+      vassert(rloc.pri == RLPri_Int);
+      vassert(addToSp == 0);
+      addInstr(env, s390_insn_move(sizeof(ULong), dst, ret));
 
-      doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
-                   expr->Iex.CCall.args, dst);
       return dst;
    }
 
@@ -3655,8 +3749,9 @@ no_memcpy_put:
    case Ist_Dirty: {
       IRType   retty;
       IRDirty* d = stmt->Ist.Dirty.details;
-      Bool     passBBP;
       HReg dst;
+      RetLoc rloc    = mk_RetLoc_INVALID();
+      UInt   addToSp = 0;
       Int i;
 
       /* Invalidate tracked values of those guest state registers that are
@@ -3672,15 +3767,15 @@ no_memcpy_put:
          }
       }
 
-      if (d->nFxState == 0)
-         vassert(!d->needsBBP);
-
-      passBBP = toBool(d->nFxState > 0 && d->needsBBP);
-
       if (d->tmp == IRTemp_INVALID) {
          /* No return value. */
-         dst = INVALID_HREG;
-         doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
+         retty = Ity_INVALID;
+         doHelperCall(&addToSp, &rloc, env, d->guard,  d->cee, retty,
+                      d->args);
+         vassert(is_sane_RetLoc(rloc));
+         vassert(rloc.pri == RLPri_None);
+         vassert(addToSp == 0);
+
          return;
       }
 
@@ -3688,9 +3783,45 @@ no_memcpy_put:
       if (retty == Ity_I64 || retty == Ity_I32
           || retty == Ity_I16 || retty == Ity_I8) {
          /* Move the returned value to the destination register */
+         HReg ret = make_gpr(S390_REGNO_RETURN_VALUE);
+
+         dst = lookupIRTemp(env, d->tmp);
+         doHelperCall(&addToSp, &rloc, env, d->guard,  d->cee, retty,
+                      d->args);
+         vassert(is_sane_RetLoc(rloc));
+         vassert(rloc.pri == RLPri_Int);
+         vassert(addToSp == 0);
+         addInstr(env, s390_insn_move(sizeof(ULong), dst, ret));
+
+         return;
+      }
+      if (retty == Ity_V128) {
+         /* we do not handle vector types yet */
+         vassert(0);
+         HReg sp = make_gpr(S390_REGNO_STACK_POINTER);
+         s390_amode *am;
+
          dst = lookupIRTemp(env, d->tmp);
-         doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
+         doHelperCall(&addToSp, &rloc, env, d->guard,  d->cee, retty,
+                      d->args);
+         vassert(is_sane_RetLoc(rloc));
+         vassert(rloc.pri == RLPri_V128SpRel);
+         vassert(addToSp >= 16);
+
+         /* rloc.spOff should be zero for s390 */
+         /* cannot use fits_unsigned_12bit(rloc.spOff), so doing
+            it explicitly */
+         vassert((rloc.spOff & 0xFFF) == rloc.spOff);
+         am = s390_amode_b12(rloc.spOff, sp);
+         // JRS 2013-Aug-08: is this correct?  Looks like we're loading
+         // only 64 bits from memory, when in fact we should be loading 128.
+         addInstr(env, s390_insn_load(8, dst, am));
+         addInstr(env, s390_insn_alu(4, S390_ALU_ADD, sp,
+                                     s390_opnd_imm(addToSp)));
          return;
+      } else {/* if (retty == Ity_V256) */
+         /* we do not handle vector types yet */
+         vassert(0);
       }
       break;
    }
index 8d17f0ef45dfbf983746b5b8e185ce010c5ed4e8..21a05a999e6f82e0adfc96d991d4513dc33986b2 100644 (file)
@@ -647,7 +647,7 @@ X86Instr* X86Instr_Call ( X86CondCode cond, Addr32 target, Int regparms,
    i->Xin.Call.regparms = regparms;
    i->Xin.Call.rloc     = rloc;
    vassert(regparms >= 0 && regparms <= 3);
-   vassert(rloc != RetLocINVALID);
+   vassert(is_sane_RetLoc(rloc));
    return i;
 }
 X86Instr* X86Instr_XDirect ( Addr32 dstGA, X86AMode* amEIP,
@@ -2383,7 +2383,8 @@ Int emit_X86Instr ( /*MB_MOD*/Bool* is_profInc,
       }
 
    case Xin_Call:
-      if (i->Xin.Call.cond != Xcc_ALWAYS && i->Xin.Call.rloc != RetLocNone) {
+      if (i->Xin.Call.cond != Xcc_ALWAYS
+          && i->Xin.Call.rloc.pri != RLPri_None) {
          /* The call might not happen (it isn't unconditional) and it
             returns a result.  In this case we will need to generate a
             control flow diamond to put 0x555..555 in the return
index 4ef69716c9a2a5f6cdbc4afde364c327fcb544a4..9ffba191b1ca26d669fb917c6fe6eb657969feac 100644 (file)
@@ -340,10 +340,23 @@ static X86AMode* advance4 ( X86AMode* am )
 
 /* Push an arg onto the host stack, in preparation for a call to a
    helper function of some kind.  Returns the number of 32-bit words
-   pushed. */
-
-static Int pushArg ( ISelEnv* env, IRExpr* arg )
+   pushed.  If we encounter an IRExprP__VECRET then we expect that
+   r_vecRetAddr will be a valid register, that holds the relevant
+   address. 
+*/
+static Int pushArg ( ISelEnv* env, IRExpr* arg, HReg r_vecRetAddr )
 {
+   if (UNLIKELY(arg == IRExprP__VECRET)) {
+      vassert(0); //ATC
+      vassert(!hregIsInvalid(r_vecRetAddr));
+      addInstr(env, X86Instr_Push(X86RMI_Reg(r_vecRetAddr)));
+      return 1;
+   }
+   if (UNLIKELY(arg == IRExprP__BBPTR)) {
+      addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP())));
+      return 1;
+   }
+   /* Else it's a "normal" expression. */
    IRType arg_ty = typeOfIRExpr(env->type_env, arg);
    if (arg_ty == Ity_I32) {
       addInstr(env, X86Instr_Push(iselIntExpr_RMI(env, arg)));
@@ -389,6 +402,12 @@ void callHelperAndClearArgs ( ISelEnv* env, X86CondCode cc,
 static
 Bool mightRequireFixedRegs ( IRExpr* e )
 {
+   if (UNLIKELY(is_IRExprP__VECRET_or_BBPTR(e))) {
+      // These are always "safe" -- either a copy of %esp in some
+      // arbitrary vreg, or a copy of %ebp, respectively.
+      return False;
+   }
+   /* Else it's a "normal" expression. */
    switch (e->tag) {
       case Iex_RdTmp: case Iex_Const: case Iex_Get: 
          return False;
@@ -398,15 +417,19 @@ Bool mightRequireFixedRegs ( IRExpr* e )
 }
 
 
-/* Do a complete function call.  guard is a Ity_Bit expression
+/* Do a complete function call.  |guard| is a Ity_Bit expression
    indicating whether or not the call happens.  If guard==NULL, the
-   call is unconditional. */
+   call is unconditional.  |retloc| is set to indicate where the
+   return value is after the call.  The caller (of this fn) must
+   generate code to add |stackAdjustAfterCall| to the stack pointer
+   after the call is done. */
 
 static
-void doHelperCall ( ISelEnv* env, 
-                    Bool passBBP, 
-                    IRExpr* guard, IRCallee* cee, IRExpr** args,
-                    RetLoc rloc )
+void doHelperCall ( /*OUT*/UInt*   stackAdjustAfterCall,
+                    /*OUT*/RetLoc* retloc,
+                    ISelEnv* env,
+                    IRExpr* guard,
+                    IRCallee* cee, IRType retTy, IRExpr** args )
 {
    X86CondCode cc;
    HReg        argregs[3];
@@ -415,11 +438,28 @@ void doHelperCall ( ISelEnv* env,
    Int         not_done_yet, n_args, n_arg_ws, stack_limit, 
                i, argreg, argregX;
 
+   /* Set default returns.  We'll update them later if needed. */
+   *stackAdjustAfterCall = 0;
+   *retloc               = mk_RetLoc_INVALID();
+
+   /* These are used for cross-checking that IR-level constraints on
+      the use of IRExprP__VECRET and IRExprP__BBPTR are observed. */
+   UInt nVECRETs = 0;
+   UInt nBBPTRs  = 0;
+
    /* Marshal args for a call, do the call, and clear the stack.
       Complexities to consider:
 
-      * if passBBP is True, %ebp (the baseblock pointer) is to be
-        passed as the first arg.
+      * The return type can be I{64,32,16,8} or V128.  In the V128
+        case, it is expected that |args| will contain the special
+        value IRExprP__VECRET, in which case this routine generates
+        code to allocate space on the stack for the vector return
+        value.  Since we are not passing any scalars on the stack, it
+        is enough to preallocate the return space before marshalling
+        any arguments, in this case.
+
+        |args| may also contain IRExprP__BBPTR, in which case the
+        value in %ebp is passed as the corresponding argument.
 
       * If the callee claims regparmness of 1, 2 or 3, we must pass the
         first 1, 2 or 3 args in registers (EAX, EDX, and ECX
@@ -463,21 +503,45 @@ void doHelperCall ( ISelEnv* env,
    */
    vassert(cee->regparms >= 0 && cee->regparms <= 3);
 
+   /* Count the number of args and also the VECRETs */
    n_args = n_arg_ws = 0;
-   while (args[n_args]) n_args++;
+   while (args[n_args]) {
+      IRExpr* arg = args[n_args];
+      n_args++;
+      if (UNLIKELY(arg == IRExprP__VECRET)) {
+         nVECRETs++;
+      } else if (UNLIKELY(arg == IRExprP__BBPTR)) {
+         nBBPTRs++;
+      }
+   }
+
+   /* If this fails, the IR is ill-formed */
+   vassert(nBBPTRs == 0 || nBBPTRs == 1);
+
+   /* If we have a VECRET, allocate space on the stack for the return
+      value, and record the stack pointer after that. */
+   HReg r_vecRetAddr = INVALID_HREG;
+   if (nVECRETs == 1) {
+      vassert(retTy == Ity_V128 || retTy == Ity_V256);
+      vassert(retTy != Ity_V256); // we don't handle that yet (if ever)
+      r_vecRetAddr = newVRegI(env);
+      sub_from_esp(env, 16);
+      addInstr(env, mk_iMOVsd_RR( hregX86_ESP(), r_vecRetAddr ));
+   } else {
+      // If either of these fail, the IR is ill-formed
+      vassert(retTy != Ity_V128 && retTy != Ity_V256);
+      vassert(nVECRETs == 0);
+   }
 
    not_done_yet = n_args;
-   if (passBBP)
-      not_done_yet++;
 
    stack_limit = cee->regparms;
-   if (cee->regparms > 0 && passBBP) stack_limit--;
 
    /* ------ BEGIN marshall all arguments ------ */
 
    /* Push (R to L) the stack-passed args, [n_args-1 .. stack_limit] */
    for (i = n_args-1; i >= stack_limit; i--) {
-      n_arg_ws += pushArg(env, args[i]);
+      n_arg_ws += pushArg(env, args[i], r_vecRetAddr);
       not_done_yet--;
    }
 
@@ -518,10 +582,18 @@ void doHelperCall ( ISelEnv* env,
                vex_printf("\n");
             }
 
+            IRExpr* arg = args[i];
             argreg--;
             vassert(argreg >= 0);
-            vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32);
-            tmpregs[argreg] = iselIntExpr_R(env, args[i]);
+            if (UNLIKELY(arg == IRExprP__VECRET)) {
+               vassert(0); //ATC
+            }
+            else if (UNLIKELY(arg == IRExprP__BBPTR)) {
+               vassert(0); //ATC
+            } else {
+               vassert(typeOfIRExpr(env->type_env, arg) == Ity_I32);
+               tmpregs[argreg] = iselIntExpr_R(env, arg);
+            }
             not_done_yet--;
          }
          for (i = stack_limit-1; i >= 0; i--) {
@@ -534,35 +606,30 @@ void doHelperCall ( ISelEnv* env,
          /* It's safe to compute all regparm args directly into their
             target registers. */
          for (i = stack_limit-1; i >= 0; i--) {
+            IRExpr* arg = args[i];
             argreg--;
             vassert(argreg >= 0);
-            vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32);
-            addInstr(env, X86Instr_Alu32R(Xalu_MOV, 
-                                          iselIntExpr_RMI(env, args[i]),
-                                          argregs[argreg]));
+            if (UNLIKELY(arg == IRExprP__VECRET)) {
+               vassert(!hregIsInvalid(r_vecRetAddr));
+               addInstr(env, X86Instr_Alu32R(Xalu_MOV,
+                                             X86RMI_Reg(r_vecRetAddr),
+                                             argregs[argreg]));
+            }
+            else if (UNLIKELY(arg == IRExprP__BBPTR)) {
+               vassert(0); //ATC
+            } else {
+               vassert(typeOfIRExpr(env->type_env, arg) == Ity_I32);
+               addInstr(env, X86Instr_Alu32R(Xalu_MOV, 
+                                             iselIntExpr_RMI(env, arg),
+                                             argregs[argreg]));
+            }
             not_done_yet--;
          }
 
       }
 
-      /* Not forgetting %ebp if needed. */
-      if (passBBP) {
-         vassert(argreg == 1);
-         addInstr(env, mk_iMOVsd_RR( hregX86_EBP(), argregs[0]));
-         not_done_yet--;
-      }
-
       /* ------ END deal with regparms ------ */
 
-   } else {
-
-      /* No regparms.  Heave %ebp on the stack if needed. */
-      if (passBBP) {
-         addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP())));
-         n_arg_ws++;
-         not_done_yet--;
-      }
-
    }
 
    vassert(not_done_yet == 0);
@@ -584,8 +651,39 @@ void doHelperCall ( ISelEnv* env,
       }
    }
 
-   /* call the helper, and get the args off the stack afterwards. */
-   callHelperAndClearArgs( env, cc, cee, n_arg_ws, rloc );
+   /* Do final checks, set the return values, and generate the call
+      instruction proper. */
+   vassert(*stackAdjustAfterCall == 0);
+   vassert(is_RetLoc_INVALID(*retloc));
+   switch (retTy) {
+         case Ity_INVALID:
+            /* Function doesn't return a value. */
+            *retloc = mk_RetLoc_simple(RLPri_None);
+            break;
+         case Ity_I64:
+            *retloc = mk_RetLoc_simple(RLPri_2Int);
+            break;
+         case Ity_I32: case Ity_I16: case Ity_I8:
+            *retloc = mk_RetLoc_simple(RLPri_Int);
+            break;
+         case Ity_V128:
+            *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 0);
+            *stackAdjustAfterCall = 16;
+            break;
+         case Ity_V256:
+            vassert(0); // ATC
+            *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 0);
+            *stackAdjustAfterCall = 32;
+            break;
+         default:
+            /* IR can denote other possible return types, but we don't
+               handle those here. */
+           vassert(0);
+   }
+
+   /* Finally, generate the call itself.  This needs the *retloc value
+      set in the switch above, which is why it's at the end. */
+   callHelperAndClearArgs( env, cc, cee, n_arg_ws, *retloc );
 }
 
 
@@ -1307,7 +1405,7 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
             addInstr(env, X86Instr_Push(X86RMI_Reg(xHi)));
             addInstr(env, X86Instr_Push(X86RMI_Reg(xLo)));
             addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn,
-                                         0, RetLocInt ));
+                                         0, mk_RetLoc_simple(RLPri_Int) ));
             add_to_esp(env, 2*4);
             addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), dst));
             return dst;
@@ -1371,8 +1469,13 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
          goto irreducible;
 
       /* Marshal args, do the call, clear stack. */
-      doHelperCall( env, False, NULL, e->Iex.CCall.cee,
-                    e->Iex.CCall.args, RetLocInt );
+      UInt   addToSp = 0;
+      RetLoc rloc    = mk_RetLoc_INVALID();
+      doHelperCall( &addToSp, &rloc, env, NULL/*guard*/,
+                    e->Iex.CCall.cee, e->Iex.CCall.retty, e->Iex.CCall.args );
+      vassert(is_sane_RetLoc(rloc));
+      vassert(rloc.pri == RLPri_Int);
+      vassert(addToSp == 0);
 
       addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), dst));
       return dst;
@@ -1890,8 +1993,15 @@ static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
       vassert(cal->Iex.CCall.retty == Ity_I32); /* else ill-typed IR */
       vassert(con->Iex.Const.con->tag == Ico_U32);
       /* Marshal args, do the call. */
-      doHelperCall( env, False, NULL, cal->Iex.CCall.cee,
-                    cal->Iex.CCall.args, RetLocInt );
+      UInt   addToSp = 0;
+      RetLoc rloc    = mk_RetLoc_INVALID();
+      doHelperCall( &addToSp, &rloc, env, NULL/*guard*/,
+                    cal->Iex.CCall.cee,
+                    cal->Iex.CCall.retty, cal->Iex.CCall.args );
+      vassert(is_sane_RetLoc(rloc));
+      vassert(rloc.pri == RLPri_Int);
+      vassert(addToSp == 0);
+      /* */
       addInstr(env, X86Instr_Alu32R(Xalu_CMP,
                                     X86RMI_Imm(con->Iex.Const.con->Ico.U32),
                                     hregX86_EAX()));
@@ -2432,7 +2542,7 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
             addInstr(env, X86Instr_Push(X86RMI_Reg(xHi)));
             addInstr(env, X86Instr_Push(X86RMI_Reg(xLo)));
             addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn,
-                                         0, RetLoc2Int ));
+                                         0, mk_RetLoc_simple(RLPri_2Int) ));
             add_to_esp(env, 4*4);
             addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
             addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
@@ -2472,7 +2582,7 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
             addInstr(env, X86Instr_Push(X86RMI_Reg(xHi)));
             addInstr(env, X86Instr_Push(X86RMI_Reg(xLo)));
             addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn,
-                                         0, RetLoc2Int ));
+                                         0, mk_RetLoc_simple(RLPri_2Int) ));
             add_to_esp(env, 3*4);
             addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
             addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
@@ -2711,7 +2821,7 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
             addInstr(env, X86Instr_Push(X86RMI_Reg(xHi)));
             addInstr(env, X86Instr_Push(X86RMI_Reg(xLo)));
             addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn,
-                                         0, RetLoc2Int ));
+                                         0, mk_RetLoc_simple(RLPri_2Int) ));
             add_to_esp(env, 2*4);
             addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
             addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
@@ -2732,8 +2842,15 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
       HReg tHi = newVRegI(env);
 
       /* Marshal args, do the call, clear stack. */
-      doHelperCall( env, False, NULL, e->Iex.CCall.cee,
-                    e->Iex.CCall.args, RetLoc2Int );
+      UInt   addToSp = 0;
+      RetLoc rloc    = mk_RetLoc_INVALID();
+      doHelperCall( &addToSp, &rloc, env, NULL/*guard*/,
+                    e->Iex.CCall.cee,
+                    e->Iex.CCall.retty, e->Iex.CCall.args );
+      vassert(is_sane_RetLoc(rloc));
+      vassert(rloc.pri == RLPri_2Int);
+      vassert(addToSp == 0);
+      /* */
 
       addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
       addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
@@ -3657,7 +3774,7 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
                                         X86AMode_IR(0, hregX86_ECX())));
          /* call the helper */
          addInstr(env, X86Instr_Call( Xcc_ALWAYS, (Addr32)fn,
-                                      3, RetLocNone ));
+                                      3, mk_RetLoc_simple(RLPri_None) ));
          /* fetch the result from memory, using %r_argp, which the
             register allocator will keep alive across the call. */
          addInstr(env, X86Instr_SseLdSt(True/*isLoad*/, dst,
@@ -3925,60 +4042,77 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
    /* --------- Call to DIRTY helper --------- */
    case Ist_Dirty: {
       IRDirty* d = stmt->Ist.Dirty.details;
-      Bool     passBBP = False;
-
-      if (d->nFxState == 0)
-         vassert(!d->needsBBP);
-
-      passBBP = toBool(d->nFxState > 0 && d->needsBBP);
 
       /* 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;
+      Bool retty_ok = False;
       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;
+         case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
+         case Ity_V128:
+            retty_ok = True; break;
          default:
             break;
       }
-      if (rloc == RetLocINVALID)
+      if (!retty_ok)
          break; /* will go to stmt_fail: */
 
-      /* Marshal args, do the call, clear stack. */
-      doHelperCall( env, passBBP, d->guard, d->cee, d->args, rloc );
+      /* Marshal args, do the call, and set the return value to
+         0x555..555 if this is a conditional call that returns a value
+         and the call is skipped. */
+      UInt   addToSp = 0;
+      RetLoc rloc    = mk_RetLoc_INVALID();
+      doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args );
+      vassert(is_sane_RetLoc(rloc));
 
       /* Now figure out what to do with the returned value, if any. */
-      if (d->tmp == IRTemp_INVALID)
-         /* No return value.  Nothing to do. */
-         return;
-
-      if (retty == Ity_I64) {
-         HReg dstHi, dstLo;
-         /* The returned value is in %edx:%eax.  Park it in the
-            register-pair associated with tmp. */
-         lookupIRTemp64( &dstHi, &dstLo, env, d->tmp);
-         addInstr(env, mk_iMOVsd_RR(hregX86_EDX(),dstHi) );
-         addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dstLo) );
-         return;
-      }
-      if (retty == Ity_I32 || retty == Ity_I16 || retty == Ity_I8) {
-         /* The returned value is in %eax.  Park it in the register
-            associated with tmp. */
-         HReg dst = lookupIRTemp(env, d->tmp);
-         addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dst) );
-         return;
+      switch (retty) {
+         case Ity_INVALID: {
+            /* No return value.  Nothing to do. */
+            vassert(d->tmp == IRTemp_INVALID);
+            vassert(rloc.pri == RLPri_None);
+            vassert(addToSp == 0);
+            return;
+         }
+         case Ity_I32: case Ity_I16: case Ity_I8: {
+            /* The returned value is in %eax.  Park it in the register
+               associated with tmp. */
+            vassert(rloc.pri == RLPri_Int);
+            vassert(addToSp == 0);
+            HReg dst = lookupIRTemp(env, d->tmp);
+            addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dst) );
+            return;
+         }
+         case Ity_I64: {
+            /* The returned value is in %edx:%eax.  Park it in the
+               register-pair associated with tmp. */
+            vassert(rloc.pri == RLPri_2Int);
+            vassert(addToSp == 0);
+            HReg dstHi, dstLo;
+            lookupIRTemp64( &dstHi, &dstLo, env, d->tmp);
+            addInstr(env, mk_iMOVsd_RR(hregX86_EDX(),dstHi) );
+            addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dstLo) );
+            return;
+         }
+         case Ity_V128: {
+            /* The returned value is on the stack, and *retloc tells
+               us where.  Fish it off the stack and then move the
+               stack pointer upwards to clear it, as directed by
+               doHelperCall. */
+            vassert(rloc.pri == RLPri_V128SpRel);
+            vassert(addToSp >= 16);
+            HReg      dst = lookupIRTemp(env, d->tmp);
+            X86AMode* am  = X86AMode_IR(rloc.spOff, hregX86_ESP());
+            addInstr(env, X86Instr_SseLdSt( True/*load*/, dst, am ));
+            add_to_esp(env, addToSp);
+            return;
+         }
+         default:
+            /*NOTREACHED*/
+            vassert(0);
       }
       break;
    }
index db5a836f519cabfb043f75bd40fd875607ad62d6..288870cc516ab67e98a4c973aeb13b0c0e1e1fb7 100644 (file)
@@ -1205,9 +1205,21 @@ void ppIRExpr ( IRExpr* e )
       ppIRCallee(e->Iex.CCall.cee);
       vex_printf("(");
       for (i = 0; e->Iex.CCall.args[i] != NULL; i++) {
-        ppIRExpr(e->Iex.CCall.args[i]);
-        if (e->Iex.CCall.args[i+1] != NULL)
+        IRExpr* arg = e->Iex.CCall.args[i];
+        /* We don't actually expect VECRET or BBPTR here -- BBPTR is
+           never allowable; VECRET is in principle allowable but at
+           present isn't supported.  But they are handled for
+           completeness anyway. */
+        if (arg == IRExprP__VECRET) {
+          vex_printf("VECRET");
+        } else if (arg == IRExprP__BBPTR) {
+          vex_printf("BBPTR");
+        } else {
+          ppIRExpr(arg);
+        }
+        if (e->Iex.CCall.args[i+1] != NULL) {
           vex_printf(",");
+        }
       }
       vex_printf("):");
       ppIRType(e->Iex.CCall.retty);
@@ -1246,8 +1258,6 @@ void ppIRDirty ( IRDirty* d )
    }
    vex_printf("DIRTY ");
    ppIRExpr(d->guard);
-   if (d->needsBBP)
-      vex_printf(" NeedsBBP");
    if (d->mFx != Ifx_None) {
       vex_printf(" ");
       ppIREffect(d->mFx);
@@ -1270,7 +1280,14 @@ void ppIRDirty ( IRDirty* d )
    ppIRCallee(d->cee);
    vex_printf("(");
    for (i = 0; d->args[i] != NULL; i++) {
-      ppIRExpr(d->args[i]);
+      IRExpr* arg = d->args[i];
+      if (arg == IRExprP__VECRET) {
+         vex_printf("VECRET");
+      } else if (arg == IRExprP__BBPTR) {
+         vex_printf("BBPTR");
+      } else {
+         ppIRExpr(arg);
+      }
       if (d->args[i+1] != NULL) {
          vex_printf(",");
       }
@@ -1838,7 +1855,6 @@ IRDirty* emptyIRDirty ( void ) {
    d->mFx      = Ifx_None;
    d->mAddr    = NULL;
    d->mSize    = 0;
-   d->needsBBP = False;
    d->nFxState = 0;
    return d;
 }
@@ -2174,7 +2190,6 @@ IRDirty* deepCopyIRDirty ( IRDirty* d )
    d2->mFx   = d->mFx;
    d2->mAddr = d->mAddr==NULL ? NULL : deepCopyIRExpr(d->mAddr);
    d2->mSize = d->mSize;
-   d2->needsBBP = d->needsBBP;
    d2->nFxState = d->nFxState;
    for (i = 0; i < d2->nFxState; i++)
       d2->fxState[i] = d->fxState[i];
@@ -3361,6 +3376,17 @@ Bool isPlausibleIRType ( IRType ty )
    }
 */
 
+static inline Bool isIRAtom_or_VECRET_or_BBPTR ( IRExpr* e ) {
+   /* Use this rather roundabout scheme so as to try and have the
+      number of additional conditional branches be 1 in the common
+      (non-VECRET, non-BBPTR) case, rather than 2. */
+   if (UNLIKELY(((HWord)e) & 1)) {
+      return e == IRExprP__VECRET || e == IRExprP__BBPTR;
+   } else {
+      return isIRAtom(e);
+   }
+}
+
 Bool isFlatIRStmt ( IRStmt* st )
 {
    Int      i;
@@ -3449,7 +3475,7 @@ Bool isFlatIRStmt ( IRStmt* st )
          if (!isIRAtom(di->guard)) 
             return False;
          for (i = 0; di->args[i]; i++)
-            if (!isIRAtom(di->args[i])) 
+            if (!isIRAtom_or_VECRET_or_BBPTR(di->args[i])) 
                return False;
          if (di->mAddr && !isIRAtom(di->mAddr)) 
             return False;
@@ -3589,8 +3615,17 @@ void useBeforeDef_Expr ( IRSB* bb, IRStmt* stmt, IRExpr* expr, Int* def_counts )
       case Iex_Const:
          break;
       case Iex_CCall:
-         for (i = 0; expr->Iex.CCall.args[i]; i++)
-            useBeforeDef_Expr(bb,stmt,expr->Iex.CCall.args[i],def_counts);
+         for (i = 0; expr->Iex.CCall.args[i]; i++) {
+            IRExpr* arg = expr->Iex.CCall.args[i];
+            if (UNLIKELY(((HWord)arg) & 1)) {
+               /* These aren't allowed in CCall lists.  Let's detect
+                  and throw them out here, though, rather than
+                  segfaulting a bit later on. */
+               sanityCheckFail(bb,stmt, "IRExprP__* value in CCall arg list");
+            } else {
+               useBeforeDef_Expr(bb,stmt,arg,def_counts);
+            }
+         }
          break;
       case Iex_ITE:
          useBeforeDef_Expr(bb,stmt,expr->Iex.ITE.cond,def_counts);
@@ -3662,8 +3697,15 @@ void useBeforeDef_Stmt ( IRSB* bb, IRStmt* stmt, Int* def_counts )
          break;
       case Ist_Dirty:
          d = stmt->Ist.Dirty.details;
-         for (i = 0; d->args[i] != NULL; i++)
-            useBeforeDef_Expr(bb,stmt,d->args[i],def_counts);
+         for (i = 0; d->args[i] != NULL; i++) {
+            IRExpr* arg = d->args[i];
+            if (UNLIKELY(((HWord)arg) & 1)) {
+               /* This is ensured by isFlatIRStmt */
+               vassert(arg == IRExprP__VECRET || arg == IRExprP__BBPTR);
+            } else {
+               useBeforeDef_Expr(bb,stmt,arg,def_counts);
+            }
+         }
          if (d->mFx != Ifx_None)
             useBeforeDef_Expr(bb,stmt,d->mAddr,def_counts);
          break;
@@ -3855,7 +3897,10 @@ void tcExpr ( IRSB* bb, IRStmt* stmt, IRExpr* expr, IRType gWordTy )
          for (i = 0; expr->Iex.CCall.args[i]; i++) {
             if (i >= 32)
                sanityCheckFail(bb,stmt,"Iex.CCall: > 32 args");
-            tcExpr(bb,stmt, expr->Iex.CCall.args[i], gWordTy);
+            IRExpr* arg = expr->Iex.CCall.args[i];
+            if (UNLIKELY(is_IRExprP__VECRET_or_BBPTR(arg)))
+               sanityCheckFail(bb,stmt,"Iex.CCall.args: is VECRET/BBPTR");
+            tcExpr(bb,stmt, arg, gWordTy);
          }
          if (expr->Iex.CCall.retty == Ity_I1)
             sanityCheckFail(bb,stmt,"Iex.CCall.retty: cannot return :: Ity_I1");
@@ -3877,7 +3922,7 @@ void tcExpr ( IRSB* bb, IRStmt* stmt, IRExpr* expr, IRType gWordTy )
              != typeOfIRExpr(tyenv, expr->Iex.ITE.iffalse))
             sanityCheckFail(bb,stmt,"Iex.ITE: iftrue/iffalse mismatch");
          break;
-       default: 
+      default: 
          vpanic("tcExpr");
    }
 }
@@ -4054,7 +4099,7 @@ void tcStmt ( IRSB* bb, IRStmt* stmt, IRType gWordTy )
          }
          break;
       }
-      case Ist_Dirty:
+      case Ist_Dirty: {
          /* Mostly check for various kinds of ill-formed dirty calls. */
          d = stmt->Ist.Dirty.details;
          if (d->cee == NULL) goto bad_dirty;
@@ -4069,8 +4114,6 @@ void tcStmt ( IRSB* bb, IRStmt* stmt, IRType gWordTy )
          }
          if (d->nFxState < 0 || d->nFxState > VEX_N_FXSTATE)
             goto bad_dirty;
-         if (d->nFxState == 0 && d->needsBBP)
-            goto bad_dirty;
          for (i = 0; i < d->nFxState; i++) {
             if (d->fxState[i].fx == Ifx_None) goto bad_dirty;
             if (d->fxState[i].size <= 0) goto bad_dirty;
@@ -4090,19 +4133,68 @@ void tcStmt ( IRSB* bb, IRStmt* stmt, IRType gWordTy )
          if (typeOfIRExpr(tyenv, d->guard) != Ity_I1)
             sanityCheckFail(bb,stmt,"IRStmt.Dirty.guard not :: Ity_I1");
          /* check types, minimally */
-         if (d->tmp != IRTemp_INVALID
-             && typeOfIRTemp(tyenv, d->tmp) == Ity_I1)
-            sanityCheckFail(bb,stmt,"IRStmt.Dirty.dst :: Ity_I1");
+         IRType retTy = Ity_INVALID;
+         if (d->tmp != IRTemp_INVALID) {
+            retTy = typeOfIRTemp(tyenv, d->tmp);
+            if (retTy == Ity_I1)
+               sanityCheckFail(bb,stmt,"IRStmt.Dirty.dst :: Ity_I1");
+         }
+         UInt nVECRETs = 0, nBBPTRs = 0;
          for (i = 0; d->args[i] != NULL; i++) {
             if (i >= 32)
                sanityCheckFail(bb,stmt,"IRStmt.Dirty: > 32 args");
-            if (typeOfIRExpr(tyenv, d->args[i]) == Ity_I1)
-               sanityCheckFail(bb,stmt,"IRStmt.Dirty.arg[i] :: Ity_I1");
+            IRExpr* arg = d->args[i];
+            if (UNLIKELY(((HWord)arg) & 1)) {
+               if (arg == IRExprP__VECRET) {
+                  nVECRETs++;
+               } else
+               if (arg == IRExprP__BBPTR) {
+                  nBBPTRs++;
+               } else {
+                  /* The impossibility of failure is ensured by
+                     isFlatIRStmt */
+                  vassert(0);
+               }
+            } else {
+               if (typeOfIRExpr(tyenv, arg) == Ity_I1)
+                  sanityCheckFail(bb,stmt,"IRStmt.Dirty.arg[i] :: Ity_I1");
+            }
+            if (nBBPTRs > 1) {
+               sanityCheckFail(bb,stmt,"IRStmt.Dirty.args: > 1 BBPTR arg");
+            }
+            if (nVECRETs == 1) {
+               /* Fn must return V128 or V256. */
+               if (retTy != Ity_V128 && retTy != Ity_V256)
+                  sanityCheckFail(bb,stmt,
+                                  "IRStmt.Dirty.args: VECRET present, "
+                                  "but fn does not return V128 or V256");
+            } else if (nVECRETs == 0) {
+               /* Fn must not return V128 or V256 */
+               if (retTy == Ity_V128 || retTy == Ity_V256)
+                  sanityCheckFail(bb,stmt,
+                                  "IRStmt.Dirty.args: VECRET not present, "
+                                  "but fn returns V128 or V256");
+            } else {
+               sanityCheckFail(bb,stmt,
+                               "IRStmt.Dirty.args: > 1 VECRET present");
+            }
          }
-         break;
+         if (nBBPTRs > 1) {
+            sanityCheckFail(bb,stmt,
+                            "IRStmt.Dirty.args: > 1 BBPTR present");
+         }
+         /* If you ask for the baseblock pointer, you have to make
+            some declaration about access to the guest state too. */
+         if (d->nFxState == 0 && nBBPTRs != 0) {
+            sanityCheckFail(bb,stmt,
+                            "IRStmt.Dirty.args: BBPTR requested, "
+                            "but no fxState declared");
+         }
+        break;
          bad_dirty:
          sanityCheckFail(bb,stmt,"IRStmt.Dirty: ill-formed");
          break;
+      }
       case Ist_NoOp:
          break;
       case Ist_MBE:
index 05963c5e858eb0d5d875663390112f5736896dfe..ebe24f7f920dc4ba0b8eeb95d278ee21681ba1b5 100644 (file)
@@ -486,8 +486,11 @@ static void flatten_Stmt ( IRSB* bb, IRStmt* st )
             vassert(d2->mAddr == NULL);
          }
          d2->guard = flatten_Expr(bb, d2->guard);
-         for (i = 0; d2->args[i]; i++)
-            d2->args[i] = flatten_Expr(bb, d2->args[i]);
+         for (i = 0; d2->args[i]; i++) {
+            IRExpr* arg = d2->args[i];
+            if (LIKELY(!is_IRExprP__VECRET_or_BBPTR(arg)))
+               d2->args[i] = flatten_Expr(bb, arg);
+         }
          addStmtToIRSB(bb, IRStmt_Dirty(d2));
          break;
       case Ist_NoOp:
@@ -2560,8 +2563,11 @@ static IRStmt* subst_and_fold_Stmt ( IRExpr** env, IRStmt* st )
          vassert(isIRAtom(d2->guard));
          d2->guard = fold_Expr(env, subst_Expr(env, d2->guard));
          for (i = 0; d2->args[i]; i++) {
-            vassert(isIRAtom(d2->args[i]));
-            d2->args[i] = fold_Expr(env, subst_Expr(env, d2->args[i]));
+            IRExpr* arg = d2->args[i];
+            if (LIKELY(!is_IRExprP__VECRET_or_BBPTR(arg))) {
+               vassert(isIRAtom(arg));
+               d2->args[i] = fold_Expr(env, subst_Expr(env, arg));
+            }
          }
          return IRStmt_Dirty(d2);
       }
@@ -2897,8 +2903,11 @@ static void addUses_Stmt ( Bool* set, IRStmt* st )
          if (d->mFx != Ifx_None)
             addUses_Expr(set, d->mAddr);
          addUses_Expr(set, d->guard);
-         for (i = 0; d->args[i] != NULL; i++)
-            addUses_Expr(set, d->args[i]);
+         for (i = 0; d->args[i] != NULL; i++) {
+            IRExpr* arg = d->args[i];
+            if (LIKELY(!is_IRExprP__VECRET_or_BBPTR(arg)))
+               addUses_Expr(set, arg);
+         }
          return;
       case Ist_NoOp:
       case Ist_IMark:
@@ -4941,8 +4950,11 @@ static void aoccCount_Stmt ( UShort* uses, IRStmt* st )
          if (d->mFx != Ifx_None)
             aoccCount_Expr(uses, d->mAddr);
          aoccCount_Expr(uses, d->guard);
-         for (i = 0; d->args[i]; i++)
-            aoccCount_Expr(uses, d->args[i]);
+         for (i = 0; d->args[i]; i++) {
+            IRExpr* arg = d->args[i];
+            if (LIKELY(!is_IRExprP__VECRET_or_BBPTR(arg)))
+               aoccCount_Expr(uses, arg);
+         }
          return;
       case Ist_NoOp:
       case Ist_IMark:
@@ -5310,8 +5322,11 @@ static IRStmt* atbSubst_Stmt ( ATmpInfo* env, IRStmt* st )
          if (d2->mFx != Ifx_None)
             d2->mAddr = atbSubst_Expr(env, d2->mAddr);
          d2->guard = atbSubst_Expr(env, d2->guard);
-         for (i = 0; d2->args[i]; i++)
-            d2->args[i] = atbSubst_Expr(env, d2->args[i]);
+         for (i = 0; d2->args[i]; i++) {
+            IRExpr* arg = d2->args[i];
+            if (LIKELY(!is_IRExprP__VECRET_or_BBPTR(arg)))
+               d2->args[i] = atbSubst_Expr(env, arg);
+         }
          return IRStmt_Dirty(d2);
       default: 
          vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
@@ -5333,11 +5348,13 @@ static Bool dirty_helper_puts ( const IRDirty *d,
    Int i;
 
    /* Passing the guest state pointer opens the door to modifying the
-      guest state under the covers. It's not allowed, but let's be
+      guest state under the covers.  It's not allowed, but let's be
       extra conservative and assume the worst. */
-   if (d->needsBBP) {
-      *requiresPreciseMemExns = True;
-      return True;
+   for (i = 0; d->args[i]; i++) {
+      if (UNLIKELY(d->args[i] == IRExprP__BBPTR)) {
+         *requiresPreciseMemExns = True;
+         return True;
+      }
    }
 
    /* Check the side effects on the guest state */
@@ -5351,7 +5368,8 @@ static Bool dirty_helper_puts ( const IRDirty *d,
          Int nRepeats = d->fxState[i].nRepeats;
          Int repeatLen = d->fxState[i].repeatLen;
 
-         if (preciseMemExnsFn(offset, offset + nRepeats * repeatLen + size - 1)) {
+         if (preciseMemExnsFn(offset,
+                              offset + nRepeats * repeatLen + size - 1)) {
             *requiresPreciseMemExns = True;
             return True;
          }
@@ -5779,8 +5797,11 @@ static void considerExpensives ( /*OUT*/Bool* hasGetIorPutI,
          case Ist_Dirty:
             d = st->Ist.Dirty.details;
             vassert(isIRAtom(d->guard));
-            for (j = 0; d->args[j]; j++)
-               vassert(isIRAtom(d->args[j]));
+            for (j = 0; d->args[j]; j++) {
+               IRExpr* arg = d->args[j];
+               if (LIKELY(!is_IRExprP__VECRET_or_BBPTR(arg)))
+                  vassert(isIRAtom(arg));
+            }
             if (d->mFx != Ifx_None)
                vassert(isIRAtom(d->mAddr));
             break;
index 6297a5de984056e2b1c139ef8d37ae28371d0a90..287e7c8b0653574b34ebcf0f1082f4fa7d20003d 100644 (file)
@@ -432,11 +432,11 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta )
          emit        = (Int(*)(Bool*,UChar*,Int,HInstr*,Bool,
                                void*,void*,void*,void*))
                        emit_MIPSInstr;
-#if defined(VKI_LITTLE_ENDIAN)
+#        if defined(VKI_LITTLE_ENDIAN)
          host_is_bigendian = False;
-#elif defined(VKI_BIG_ENDIAN)
+#        elif defined(VKI_BIG_ENDIAN)
          host_is_bigendian = True;
-#endif
+#        endif
          host_word_type    = Ity_I32;
          vassert(are_valid_hwcaps(VexArchMIPS32, vta->archinfo_host.hwcaps));
          break;
@@ -456,11 +456,11 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta )
          emit        = (Int(*)(Bool*,UChar*,Int,HInstr*,Bool,
                                void*,void*,void*,void*))
                        emit_MIPSInstr;
-#if defined(VKI_LITTLE_ENDIAN)
+#        if defined(VKI_LITTLE_ENDIAN)
          host_is_bigendian = False;
-#elif defined(VKI_BIG_ENDIAN)
+#        elif defined(VKI_BIG_ENDIAN)
          host_is_bigendian = True;
-#endif
+#        endif
          host_word_type    = Ity_I64;
          vassert(are_valid_hwcaps(VexArchMIPS64, vta->archinfo_host.hwcaps));
          break;
index bf35796149274312a942871c967cc1cd117b3316..ca109963dd5ce9409cc776e1c24150bc52b23698 100644 (file)
@@ -1853,6 +1853,12 @@ struct _IRExpr {
          Ist_Dirty inhibits various IR optimisations and so can cause
          quite poor code to be generated.  Try to avoid it.
 
+         In principle it would be allowable to have the arg vector
+         contain the special value IRExprP__VECRET, although not
+         IRExprP__BBPTR.  However, at the moment there is no
+         requirement for clean helper calls to be able to return V128
+         or V256 values.  Hence this is not allowed.
+
          ppIRExpr output: <cee>(<args>):<retty>
                       eg. foo{0x80489304}(t1, t2):I32
       */
@@ -1894,6 +1900,34 @@ struct _IRQop {
    IRExpr* arg4;     /* operand 4 */
 };
 
+
+/* Two special constants of type IRExpr*, which can ONLY be used in
+   argument lists for dirty helper calls (IRDirty.args) and in NO
+   OTHER PLACES.  And then only in very limited ways.  These constants
+   are not pointer-aligned and hence can't be confused with real
+   IRExpr*s nor with NULL. */
+
+/* Denotes an argument which (in the helper) takes a pointer to a
+   (naturally aligned) V128 or V256, into which the helper is expected
+   to write its result.  Use of IRExprP__VECRET is strictly
+   controlled.  If the helper returns a V128 or V256 value then
+   IRExprP__VECRET must appear exactly once in the arg list, although
+   it can appear anywhere, and the helper must have a C 'void' return
+   type.  If the helper returns any other type, IRExprP__VECRET may
+   not appear in the argument list. */
+#define IRExprP__VECRET ((IRExpr*)9)
+
+/* Denotes an void* argument which is passed to the helper, which at
+   run time will point to the thread's guest state area.  This can
+   only appear at most once in an argument list, and it may not appear
+   at all in argument lists for clean helper calls. */
+#define IRExprP__BBPTR  ((IRExpr*)17)
+
+static inline Bool is_IRExprP__VECRET_or_BBPTR ( IRExpr* e ) {
+   return e == IRExprP__VECRET || e == IRExprP__BBPTR;
+}
+
+
 /* Expression constructors. */
 extern IRExpr* IRExpr_Binder ( Int binder );
 extern IRExpr* IRExpr_Get    ( Int off, IRType ty );
@@ -2053,11 +2087,12 @@ extern void ppIRJumpKind ( IRJumpKind );
      number of times at a fixed interval, if required.
 
    Normally, code is generated to pass just the args to the helper.
-   However, if .needsBBP is set, then an extra first argument is
-   passed, which is the baseblock pointer, so that the callee can
-   access the guest state.  It is invalid for .nFxState to be zero
-   but .needsBBP to be True, since .nFxState==0 is a claim that the
-   call does not access guest state.
+   However, if IRExprP__BBPTR is present in the argument list (at most
+   one instance is allowed), then the baseblock pointer is passed for
+   that arg, so that the callee can access the guest state.  It is
+   invalid for .nFxState to be zero but IRExprP__BBPTR to be present,
+   since .nFxState==0 is a claim that the call does not access guest
+   state.
 
    IMPORTANT NOTE re GUARDS: Dirty calls are strict, very strict.  The
    arguments and 'mFx' are evaluated REGARDLESS of the guard value.
@@ -2092,7 +2127,9 @@ typedef
          allowed. */
       IRCallee* cee;    /* where to call */
       IRExpr*   guard;  /* :: Ity_Bit.  Controls whether call happens */
-      IRExpr**  args;   /* arg list, ends in NULL */
+      /* The args vector may contain IRExprP__BBPTR and/or
+         IRExprP__VECRET, in both cases, at most once. */
+      IRExpr**  args;   /* arg vector, ends in NULL. */
       IRTemp    tmp;    /* to assign result to, or IRTemp_INVALID if none */
 
       /* Mem effects; we allow only one R/W/M region to be stated */
@@ -2101,7 +2138,6 @@ typedef
       Int       mSize;  /* of access, or zero if mFx==Ifx_None */
 
       /* Guest state effects; up to N allowed */
-      Bool needsBBP; /* True => also pass guest state ptr to callee */
       Int  nFxState; /* must be 0 .. VEX_N_FXSTATE */
       struct {
          IREffect fx:16;   /* read, write or modify?  Ifx_None is invalid. */