]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add a trivial new IR construction: a memory fence statement. Connect
authorJulian Seward <jseward@acm.org>
Fri, 7 Jan 2005 12:09:15 +0000 (12:09 +0000)
committerJulian Seward <jseward@acm.org>
Fri, 7 Jan 2005 12:09:15 +0000 (12:09 +0000)
up to x86 front and back ends.

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

VEX/priv/guest-x86/toIR.c
VEX/priv/host-x86/hdefs.c
VEX/priv/host-x86/hdefs.h
VEX/priv/host-x86/isel.c
VEX/priv/ir/irdefs.c
VEX/priv/ir/iropt.c
VEX/pub/libvex_ir.h

index cd58b500f0c475ffe4688f09ab8846005a5c7710..48a10f8a49adb3b4ad4646922f79389efcfb343b 100644 (file)
@@ -7842,7 +7842,9 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
        && epartIsReg(insn[2]) && gregOfRM(insn[2]) == 7) {
       vassert(sz == 4);
       delta += 3;
-      /* nothing to do */
+      /* Insert a memory fence.  It's sometimes important that these
+         are carried through to the generated code. */
+      stmt( IRStmt_MFence() );
       DIP("sfence\n");
       goto decode_success;
    }
@@ -8618,7 +8620,9 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
        && (gregOfRM(insn[2]) == 5 || gregOfRM(insn[2]) == 6)) {
       vassert(sz == 4);
       delta += 3;
-      /* nothing to do */
+      /* Insert a memory fence.  It's sometimes important that these
+         are carried through to the generated code. */
+      stmt( IRStmt_MFence() );
       DIP("%sfence\n", gregOfRM(insn[2])==5 ? "l" : "m");
       goto decode_success;
    }
index 2129e4216066622e6f1473e185882ed812153fca..c254d17a38cb54a0216a6c4c8c009a415af02de9 100644 (file)
@@ -704,6 +704,17 @@ X86Instr* X86Instr_Bsfr32 ( Bool isFwds, HReg src, HReg dst ) {
    i->Xin.Bsfr32.dst    = dst;
    return i;
 }
+X86Instr* X86Instr_MFence ( VexSubArch subarch )
+{
+   X86Instr* i           = LibVEX_Alloc(sizeof(X86Instr));
+   i->tag                = Xin_MFence;
+   i->Xin.MFence.subarch = subarch;
+   vassert(subarch == VexSubArchX86_sse0
+           || subarch == VexSubArchX86_sse1
+           || subarch == VexSubArchX86_sse2);
+   return i;
+}
+
 X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst ) {
    X86Instr* i        = LibVEX_Alloc(sizeof(X86Instr));
    i->tag             = Xin_FpUnary;
@@ -980,6 +991,10 @@ void ppX86Instr ( X86Instr* i ) {
          vex_printf(",");
          ppHRegX86(i->Xin.Bsfr32.dst);
          return;
+      case Xin_MFence:
+         vex_printf("mfence(%s)",
+                    LibVEX_ppVexSubArch(i->Xin.MFence.subarch));
+         return;
       case Xin_FpUnary:
          vex_printf("g%sD ", showX86FpOp(i->Xin.FpUnary.op));
          ppHRegX86(i->Xin.FpUnary.src);
@@ -1230,6 +1245,8 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i)
          addHRegUse(u, HRmRead, i->Xin.Bsfr32.src);
          addHRegUse(u, HRmWrite, i->Xin.Bsfr32.dst);
          return;
+      case Xin_MFence:
+         return;
       case Xin_FpUnary:
          addHRegUse(u, HRmRead, i->Xin.FpUnary.src);
          addHRegUse(u, HRmWrite, i->Xin.FpUnary.dst);
@@ -1408,6 +1425,8 @@ void mapRegs_X86Instr (HRegRemap* m, X86Instr* i)
          mapReg(m, &i->Xin.Bsfr32.src);
          mapReg(m, &i->Xin.Bsfr32.dst);
          return;
+      case Xin_MFence:
+         return;
       case Xin_FpUnary:
          mapReg(m, &i->Xin.FpUnary.src);
          mapReg(m, &i->Xin.FpUnary.dst);
@@ -2317,6 +2336,33 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i )
       p = doAMode_R(p, i->Xin.Bsfr32.dst, i->Xin.Bsfr32.src);
       goto done;
 
+   case Xin_MFence:
+      /* see comment in hdefs.h re this insn */
+vex_printf("EMIT FENCE\n");
+      switch (i->Xin.MFence.subarch) {
+         case VexSubArchX86_sse0:
+            vassert(0); /* awaiting test case */
+            /* lock addl $0,0(%esp) */
+            *p++ = 0xF0; *p++ = 0x83; *p++ = 0x44; 
+            *p++ = 0x24; *p++ = 0x00; *p++ = 0x00;
+            goto done;
+         case VexSubArchX86_sse1:
+            /* sfence */
+            *p++ = 0x0F; *p++ = 0xAE; *p++ = 0xF8;
+            /* lock addl $0,0(%esp) */
+            *p++ = 0xF0; *p++ = 0x83; *p++ = 0x44; 
+            *p++ = 0x24; *p++ = 0x00; *p++ = 0x00;
+            goto done;
+         case VexSubArchX86_sse2:
+            vassert(0); /* awaiting test case */
+            /* mfence */
+            *p++ = 0x0F; *p++ = 0xAE; *p++ = 0xF0;
+            goto done;
+         default: 
+            vpanic("emit_X86Instr:mfence:subarch");
+      }
+      break;
+
    case Xin_Store:
       if (i->Xin.Store.sz == 2) {
          /* This case, at least, is simple, given that we can
index 7c550f9b763b914abc6f75151a4027df9cfb80b3..f8e74a7705206ac01afdab7a122b22b58a4123e9 100644 (file)
@@ -365,6 +365,7 @@ typedef
       Xin_Store,     /* store 16/8 bit value in memory */
       Xin_Set32,     /* convert condition code to 32-bit value */
       Xin_Bsfr32,    /* 32-bit bsf/bsr */
+      Xin_MFence,    /* mem fence (not just sse2, but sse0 and 1 too) */
 
       Xin_FpUnary,   /* FP fake unary op */
       Xin_FpBinary,  /* FP fake binary op */
@@ -490,6 +491,16 @@ typedef
             HReg src;
             HReg dst;
          } Bsfr32;
+         /* Mem fence (not just sse2, but sse0 and 1 too).  In short,
+            an insn which flushes all preceding loads and stores as
+            much as possible before continuing.  On SSE2 we emit a
+            real "mfence", on SSE1 "sfence ; lock addl $0,0(%esp)" and
+            on SSE0 "lock addl $0,0(%esp)".  This insn therefore
+            carries the subarch so the assembler knows what to
+            emit. */
+         struct {
+            VexSubArch subarch;
+         } MFence;
 
          /* X86 Floating point (fake 3-operand, "flat reg file" insns) */
          struct {
@@ -624,6 +635,7 @@ extern X86Instr* X86Instr_LoadEX    ( UChar szSmall, Bool syned,
 extern X86Instr* X86Instr_Store     ( UChar sz, HReg src, X86AMode* dst );
 extern X86Instr* X86Instr_Set32     ( X86CondCode cond, HReg dst );
 extern X86Instr* X86Instr_Bsfr32    ( Bool isFwds, HReg src, HReg dst );
+extern X86Instr* X86Instr_MFence    ( VexSubArch );
 
 extern X86Instr* X86Instr_FpUnary   ( X86FpOp op, HReg src, HReg dst );
 extern X86Instr* X86Instr_FpBinary  ( X86FpOp op, HReg srcL, HReg srcR, HReg dst );
index f667a5930fe5b919346c956bf33de0f6abdf05d1..71a3fc702146c367f2d0ad687d2d5099d643de7f 100644 (file)
@@ -3098,6 +3098,11 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
       break;
    }
 
+   /* --------- MEM FENCE --------- */
+   case Ist_MFence:
+      addInstr(env, X86Instr_MFence(env->subarch));
+      return;
+
    /* --------- EXIT --------- */
    case Ist_Exit: {
       X86RI*      dst;
index a1d9dc88883e02aec2ddf335393869ca67c105fe..1e01332e1138d9a8d960f1eec9c83e6ecc1aad30 100644 (file)
 
 void ppIRType ( IRType ty )
 {
-  switch (ty) {
-    case Ity_INVALID: vex_printf("Ity_INVALID"); break;
-    case Ity_I1:      vex_printf( "I1");  break;
-    case Ity_I8:      vex_printf( "I8");  break;
-    case Ity_I16:     vex_printf( "I16"); break;
-    case Ity_I32:     vex_printf( "I32"); break;
-    case Ity_I64:     vex_printf( "I64"); break;
-    case Ity_F32:     vex_printf( "F32"); break;
-    case Ity_F64:     vex_printf( "F64"); break;
-    case Ity_V128:    vex_printf( "V128"); break;
-    default: vex_printf("ty = 0x%x\n", (Int)ty);
-             vpanic("ppIRType");
-  }
+   switch (ty) {
+      case Ity_INVALID: vex_printf("Ity_INVALID"); break;
+      case Ity_I1:      vex_printf( "I1");  break;
+      case Ity_I8:      vex_printf( "I8");  break;
+      case Ity_I16:     vex_printf( "I16"); break;
+      case Ity_I32:     vex_printf( "I32"); break;
+      case Ity_I64:     vex_printf( "I64"); break;
+      case Ity_F32:     vex_printf( "F32"); break;
+      case Ity_F64:     vex_printf( "F64"); break;
+      case Ity_V128:    vex_printf( "V128"); break;
+      default: vex_printf("ty = 0x%x\n", (Int)ty);
+               vpanic("ppIRType");
+   }
 }
 
 void ppIRConst ( IRConst* con )
@@ -539,6 +539,9 @@ void ppIRStmt ( IRStmt* s )
       case Ist_Dirty:
          ppIRDirty(s->Ist.Dirty.details);
          break;
+      case Ist_MFence:
+         vex_printf("IRMemoryFence");
+         break;
       case Ist_Exit:
          vex_printf( "if (" );
          ppIRExpr(s->Ist.Exit.guard);
@@ -871,6 +874,12 @@ IRStmt* IRStmt_Dirty ( IRDirty* d )
    s->Ist.Dirty.details = d;
    return s;
 }
+IRStmt* IRStmt_MFence ( void )
+{
+   IRStmt* s = LibVEX_Alloc(sizeof(IRStmt));
+   s->tag    = Ist_MFence;
+   return s;
+}
 IRStmt* IRStmt_Exit ( IRExpr* guard, IRJumpKind jk, IRConst* dst ) {
    IRStmt* s         = LibVEX_Alloc(sizeof(IRStmt));
    s->tag            = Ist_Exit;
@@ -1495,6 +1504,8 @@ Bool isFlatIRStmt ( IRStmt* st )
          if (di->mAddr && !isAtom(di->mAddr)) 
             return False;
          return True;
+      case Ist_MFence:
+         return True;
       case Ist_Exit:
          return isAtom(st->Ist.Exit.guard);
       default: 
@@ -1651,6 +1662,8 @@ void useBeforeDef_Stmt ( IRBB* bb, IRStmt* stmt, Int* def_counts )
          if (d->mFx != Ifx_None)
             useBeforeDef_Expr(bb,stmt,d->mAddr,def_counts);
          break;
+      case Ist_MFence:
+         break;
       case Ist_Exit:
          useBeforeDef_Expr(bb,stmt,stmt->Ist.Exit.guard,def_counts);
          break;
@@ -1838,7 +1851,8 @@ void tcStmt ( IRBB* bb, IRStmt* stmt, IRType gWordTy )
          break;
          bad_dirty:
          sanityCheckFail(bb,stmt,"IRStmt.Dirty: ill-formed");
-
+      case Ist_MFence:
+         break;
       case Ist_Exit:
          tcExpr( bb, stmt, stmt->Ist.Exit.guard, gWordTy );
          if (typeOfIRExpr(tyenv,stmt->Ist.Exit.guard) != Ity_I1)
index 7570b76765bb6983bff2e3ca7a589ffa791412aa..50dd02dcaef8fc587317db9854e42d144c16a818 100644 (file)
@@ -408,6 +408,9 @@ static void flatten_Stmt ( IRBB* bb, IRStmt* st )
             d2->args[i] = flatten_Expr(bb, d2->args[i]);
          addStmtToIRBB(bb, IRStmt_Dirty(d2));
          break;
+      case Ist_MFence:
+         addStmtToIRBB(bb, st);
+         break;
       case Ist_Exit:
          e1 = flatten_Expr(bb, st->Ist.Exit.guard);
          addStmtToIRBB(bb, IRStmt_Exit(e1, st->Ist.Exit.jk,
@@ -664,6 +667,9 @@ static void handle_gets_Stmt (
          state requiring precise exceptions needs to be flushed.  The
          crude solution is just to flush everything; we could easily
          enough do a lot better if needed. */
+      /* Probably also overly-conservative, but also dump everything
+         if we hit a memory fence. */
+      case Ist_MFence:
       case Ist_Dirty:
          for (j = 0; j < env->used; j++)
             env->inuse[j] = False;
@@ -1320,6 +1326,9 @@ static IRStmt* subst_and_fold_Stmt ( IRExpr** env, IRStmt* st )
          return IRStmt_Dirty(d2);
       }
 
+      case Ist_MFence:
+         return IRStmt_MFence();
+
       case Ist_Exit: {
          IRExpr* fcond;
          vassert(isAtom(st->Ist.Exit.guard));
@@ -1505,6 +1514,8 @@ static void addUses_Stmt ( Bool* set, IRStmt* st )
          for (i = 0; d->args[i] != NULL; i++)
             addUses_Expr(set, d->args[i]);
          return;
+      case Ist_MFence:
+         return;
       case Ist_Exit:
          addUses_Expr(set, st->Ist.Exit.guard);
          return;
@@ -2932,6 +2943,8 @@ static void occCount_Stmt ( TmpInfo** env, IRStmt* st )
          for (i = 0; d->args[i]; i++)
             occCount_Expr(env, d->args[i]);
          return;
+      case Ist_MFence:
+         return;
       case Ist_Exit:
          occCount_Expr(env, st->Ist.Exit.guard);
          return;
@@ -3062,6 +3075,8 @@ static IRStmt* tbSubst_Stmt ( TmpInfo** env, IRStmt* st )
                    st->Ist.Exit.jk,
                    st->Ist.Exit.dst
                 );
+      case Ist_MFence:
+         return IRStmt_MFence();
       case Ist_Dirty:
          d = st->Ist.Dirty.details;
          d2 = emptyIRDirty();
@@ -3282,8 +3297,11 @@ static void dumpInvalidated ( TmpInfo** env, IRBB* bb, /*INOUT*/Int* j )
          appeared.  (Stupid algorithm): first, mark all bindings which
          need to be dumped.  Then, dump them in the order in which
          they were defined. */
+
       invPut = st->tag == Ist_Put 
-               || st->tag == Ist_PutI || st->tag == Ist_Dirty;
+               || st->tag == Ist_PutI 
+               || st->tag == Ist_Dirty;
+
       invStore = st->tag == Ist_STle
                  || st->tag == Ist_Dirty;
 
@@ -3294,7 +3312,8 @@ static void dumpInvalidated ( TmpInfo** env, IRBB* bb, /*INOUT*/Int* j )
          if (!ti->expr)
             continue;
 
-         /* We have to invalidate this binding. */
+         /* Do we have to invalidate this binding? */
+
          ti->invalidateMe 
             = /* a store invalidates loaded data */
               (ti->eDoesLoad && invStore)
@@ -3305,11 +3324,16 @@ static void dumpInvalidated ( TmpInfo** env, IRBB* bb, /*INOUT*/Int* j )
                  invalidate trees containing loads if the Put in
                  question is marked as requiring precise
                  exceptions. */
-              || (ti->eDoesLoad && invPut);
+              || (ti->eDoesLoad && invPut)
+              /* probably overly conservative: a memory fence
+                 invalidates absolutely everything, so that all
+                 computation prior to it is forced to complete before
+                 proceeding with the fence. */
+              || st->tag == Ist_MFence;
          /*
          if (ti->invalidateMe)
-           vex_printf("SET INVAL\n");
-           */
+            vex_printf("SET INVAL\n");
+         */
       }
 
       dumpInvalidated ( env, bb, &j );
@@ -3432,9 +3456,6 @@ static Bool hasGetIorPutI ( IRBB* bb )
             vassert(isAtom(st->Ist.STle.addr));
             vassert(isAtom(st->Ist.STle.data));
             break;
-         case Ist_Exit:
-            vassert(isAtom(st->Ist.Exit.guard));
-            break;
          case Ist_Dirty:
             d = st->Ist.Dirty.details;
             vassert(isAtom(d->guard));
@@ -3443,6 +3464,11 @@ static Bool hasGetIorPutI ( IRBB* bb )
             if (d->mFx != Ifx_None)
                vassert(isAtom(d->mAddr));
             break;
+         case Ist_MFence:
+            break;
+         case Ist_Exit:
+            vassert(isAtom(st->Ist.Exit.guard));
+            break;
          default: 
             ppIRStmt(st);
             vpanic("hasGetIorPutI");
index 026b5fd318a335c02cd0349b397c91a0c87e8312..6e41b42964f9feb98966f58764e553f900118aad 100644 (file)
@@ -771,6 +771,7 @@ typedef
       Ist_Tmp,    /* assign value to temporary */
       Ist_STle,   /* little-endian write to memory */
       Ist_Dirty,  /* call complex ("dirty") helper function */
+      Ist_MFence, /* memory fence */
       Ist_Exit    /* conditional exit from BB */
    } 
    IRStmtTag;
@@ -800,6 +801,8 @@ typedef
          struct {
             IRDirty* details;
          } Dirty;
+         struct {
+         } MFence;
          struct {
             IRExpr*    guard;
             IRJumpKind jk;
@@ -809,13 +812,14 @@ typedef
    }
    IRStmt;
 
-extern IRStmt* IRStmt_Put   ( Int off, IRExpr* data );
-extern IRStmt* IRStmt_PutI  ( IRArray* descr, IRExpr* ix, Int bias, 
-                              IRExpr* data );
-extern IRStmt* IRStmt_Tmp   ( IRTemp tmp, IRExpr* data );
-extern IRStmt* IRStmt_STle  ( IRExpr* addr, IRExpr* data );
-extern IRStmt* IRStmt_Dirty ( IRDirty* details );
-extern IRStmt* IRStmt_Exit  ( IRExpr* guard, IRJumpKind jk, IRConst* dst );
+extern IRStmt* IRStmt_Put    ( Int off, IRExpr* data );
+extern IRStmt* IRStmt_PutI   ( IRArray* descr, IRExpr* ix, Int bias, 
+                               IRExpr* data );
+extern IRStmt* IRStmt_Tmp    ( IRTemp tmp, IRExpr* data );
+extern IRStmt* IRStmt_STle   ( IRExpr* addr, IRExpr* data );
+extern IRStmt* IRStmt_Dirty  ( IRDirty* details );
+extern IRStmt* IRStmt_MFence ( void );
+extern IRStmt* IRStmt_Exit   ( IRExpr* guard, IRJumpKind jk, IRConst* dst );
 
 extern IRStmt* dopyIRStmt ( IRStmt* );