Merge patch from JeremyF:

39-lock-prefix

Add a new UInstr LOCK to represent a "lock" prefix in the instruction
stream. This has the same semantics as NOP, but allows a skin to tell
whether a group of UInstrs associated with an x86 instruction are
meant to be locked.

HELGRIND: uses the LOCK UInstr to automatically take and release a
special __BUS_HARDWARE_LOCK__ around locked instructions. This only
works properly if all instructions touching a given address are locked
(even reads).


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1310 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/addrcheck/ac_main.c b/addrcheck/ac_main.c
index 7eb355d..984cc15 100644
--- a/addrcheck/ac_main.c
+++ b/addrcheck/ac_main.c
@@ -1752,7 +1752,7 @@
       u_in = &cb_in->instrs[i];
 
       switch (u_in->opcode) {
-         case NOP:  case CALLM_E:  case CALLM_S:
+         case NOP:  case LOCK:  case CALLM_E:  case CALLM_S:
             break;
 
          /* For memory-ref instrs, copy the data_addr into a temporary to be
diff --git a/cachegrind/cg_main.c b/cachegrind/cg_main.c
index c288647..7a93fc2 100644
--- a/cachegrind/cg_main.c
+++ b/cachegrind/cg_main.c
@@ -731,7 +731,7 @@
       if (instrumented_Jcond) sk_assert(u_in->opcode == JMP);
 
       switch (u_in->opcode) {
-         case NOP:  case CALLM_E:  case CALLM_S:
+         case NOP:  case LOCK:  case CALLM_E:  case CALLM_S:
             break;
 
          /* For memory-ref instrs, copy the data_addr into a temporary to be
diff --git a/coregrind/vg_from_ucode.c b/coregrind/vg_from_ucode.c
index d08c505..769785d 100644
--- a/coregrind/vg_from_ucode.c
+++ b/coregrind/vg_from_ucode.c
@@ -1981,7 +1981,7 @@
    old_emitted_code_used = emitted_code_used;
    
    switch (u->opcode) {
-      case NOP: case CALLM_S: case CALLM_E: break;
+      case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
 
       case INCEIP: {
         /* Note: Redundant INCEIP merging.  A potentially useful
diff --git a/coregrind/vg_to_ucode.c b/coregrind/vg_to_ucode.c
index 4912588..99bf7b1 100644
--- a/coregrind/vg_to_ucode.c
+++ b/coregrind/vg_to_ucode.c
@@ -3254,6 +3254,7 @@
    /* Skip a LOCK prefix. */
    if (getUChar(eip) == 0xF0) { 
       /* VG_(printf)("LOCK LOCK LOCK LOCK LOCK \n"); */
+      uInstr0(cb, LOCK, 0);
       eip++;
    }
 
diff --git a/coregrind/vg_translate.c b/coregrind/vg_translate.c
index 71fbb11..0b6175a 100644
--- a/coregrind/vg_translate.c
+++ b/coregrind/vg_translate.c
@@ -476,6 +476,7 @@
    case GETSEG: return LIT0 && SZ2  && CC0 &&  Se1 && TR2 &&  N3 && XOTHER;
    case USESEG: return LIT0 && SZ0  && CC0 &&  TR1 && TR2 &&  N3 && XOTHER;
    case NOP:    return LIT0 && SZ0  && CC0 &&   N1 &&  N2 &&  N3 && XOTHER;
+   case LOCK:   return LIT0 && SZ0  && CC0 &&   N1 &&  N2 &&  N3 && XOTHER;
    case GETF:   return LIT0 && SZ42 && CCr &&  TR1 &&  N2 &&  N3 && XOTHER;
    case PUTF:   return LIT0 && SZ42 && CCw &&  TR1 &&  N2 &&  N3 && XOTHER;
    case GET:    return LIT0 && SZi  && CC0 &&  AS1 && TR2 &&  N3 && XOTHER;
@@ -799,6 +800,7 @@
       case LEA1:    return "LEA1";
       case LEA2:    return "LEA2";
       case NOP:     return "NOP";
+      case LOCK:    return "LOCK";
       case GET:     return "GET";
       case PUT:     return "PUT";
       case GETF:    return "GETF";
@@ -919,7 +921,7 @@
          VG_(pp_UOperand)(u, 2, 4, False);
          break;
 
-      case NOP:
+      case NOP: case LOCK:
          break;
 
       case FPU_W:
@@ -1092,7 +1094,7 @@
       case LEA2: RD(1); RD(2); WR(3); break;
 
       case NOP:   case FPU:   case INCEIP: case CALLM_S: case CALLM_E:
-      case CLEAR: case CALLM: break;
+      case CLEAR: case CALLM: case LOCK: break;
 
       case CCALL:
          if (u->argc > 0)    RD(1); 
@@ -1225,6 +1227,7 @@
       case LEA1:
       case LEA2:
       case NOP:
+      case LOCK:
       case PUT:
       case LOAD:
       case STORE:
diff --git a/helgrind/hg_main.c b/helgrind/hg_main.c
index 85dcc80..b9b539b 100644
--- a/helgrind/hg_main.c
+++ b/helgrind/hg_main.c
@@ -1732,6 +1732,9 @@
 static void eraser_mem_help_write_4(Addr a, UInt val) REGPARM(2);
 static void eraser_mem_help_write_N(Addr a, UInt size) REGPARM(2);
 
+static void bus_lock(void);
+static void bus_unlock(void);
+
 static
 void eraser_pre_mem_read(CorePart part, ThreadState* tst,
                          Char* s, UInt base, UInt size )
@@ -1863,6 +1866,7 @@
    Int         t_size = INVALID_TEMPREG;
    Int	       ntemps;
    Bool	       *stackref = NULL;
+   Bool        locked = False;	/* lock prefix */
 
    cb = VG_(alloc_UCodeBlock)();
    cb->nextTemp = cb_in->nextTemp;
@@ -1883,6 +1887,21 @@
          case NOP: case CALLM_S: case CALLM_E:
             break;
     
+         case LOCK:
+	    locked = True;
+	    uInstr0(cb, CCALL, 0);
+	    uCCall(cb, (Addr)bus_lock, 0, 0, False);
+	    break;
+
+         case JMP: case INCEIP:
+	    if (locked) {
+	       uInstr0(cb, CCALL, 0);
+	       uCCall(cb, (Addr)bus_unlock, 0, 0, False);
+	    }
+	    locked = False;
+	    VG_(copy_UInstr)(cb, u_in);
+	    break;
+
          case GET:
 	    sk_assert(u_in->tag1 == ArchReg);
 	    sk_assert(u_in->tag2 == TempReg);
@@ -2935,6 +2954,21 @@
    clearTLS(joinee);
 }
 
+static Int __BUS_HARDWARE_LOCK__;
+
+static void bus_lock(void)
+{
+   ThreadId tid = VG_(get_current_tid)();
+   eraser_pre_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
+   eraser_post_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
+}
+
+static void bus_unlock(void)
+{
+   ThreadId tid = VG_(get_current_tid)();
+   eraser_post_mutex_unlock(tid, &__BUS_HARDWARE_LOCK__);
+}
+
 /*--------------------------------------------------------------------*/
 /*--- Client requests                                              ---*/
 /*--------------------------------------------------------------------*/
@@ -3030,6 +3064,9 @@
    VG_(register_compact_helper)((Addr) & eraser_mem_help_write_4);
    VG_(register_noncompact_helper)((Addr) & eraser_mem_help_write_N);
 
+   VG_(register_noncompact_helper)((Addr) & bus_lock);
+   VG_(register_noncompact_helper)((Addr) & bus_unlock);
+
    for(i = 0; i < LOCKSET_HASH_SZ; i++)
       lockset_hash[i] = NULL;
 
diff --git a/include/vg_skin.h b/include/vg_skin.h
index 540fe5f..10f70e7 100644
--- a/include/vg_skin.h
+++ b/include/vg_skin.h
@@ -492,6 +492,8 @@
    enum {
       NOP,         /* Null op */
 
+      LOCK,	   /* Indicate the existance of a LOCK prefix (functionally NOP) */
+
       /* Moving values around */
       GET,  PUT,   /* simulated register <--> TempReg */
       GETF, PUTF,  /* simulated %eflags  <--> TempReg */
diff --git a/lackey/lk_main.c b/lackey/lk_main.c
index 896dc18..4b79d9a 100644
--- a/lackey/lk_main.c
+++ b/lackey/lk_main.c
@@ -162,7 +162,7 @@
       u = &cb_in->instrs[i];
 
       switch (u->opcode) {
-         case NOP: case CALLM_S: case CALLM_E:
+         case NOP: case LOCK: case CALLM_S: case CALLM_E:
             break;
    
          case INCEIP:
diff --git a/memcheck/mc_translate.c b/memcheck/mc_translate.c
index f81bde3..657b998 100644
--- a/memcheck/mc_translate.c
+++ b/memcheck/mc_translate.c
@@ -541,6 +541,7 @@
 
       switch (u_in->opcode) {
 
+         case LOCK:
          case NOP:
             break;
 
@@ -1260,6 +1261,7 @@
 
          /* Deal with these quickly. */
          case NOP:
+         case LOCK:
          case INCEIP:
             break;