Update the X86 disassembler to use xacquire and xrelease when appropriate.
authorKevin Enderby <enderby@apple.com>
Thu, 20 Jun 2013 22:32:18 +0000 (22:32 +0000)
committerKevin Enderby <enderby@apple.com>
Thu, 20 Jun 2013 22:32:18 +0000 (22:32 +0000)
This is a bit tricky as the xacquire and xrelease hints use the same bytes,
0xf2 and 0xf3, as the repne and rep prefixes.

Fortunately llvm has different llvm MCInst Opcode enums for rep/xrelease
and repne/xacquire. So to make this work a boolean was added the
InternalInstruction struct as part of the Prefix state which is set with the
added logic in readPrefixes() when decoding an instruction to determine
if these prefix bytes are to be disassembled as xacquire or xrelease.  Then
we let the matcher pick the normal prefix instructionID and we change the
Opcode after that when it is set into the MCInst being created.

rdar://11019859

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@184490 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/X86/Disassembler/X86Disassembler.cpp
lib/Target/X86/Disassembler/X86DisassemblerDecoder.c
lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
test/MC/Disassembler/X86/simple-tests.txt

index ca71c4f351911d2e219c9a40e5d29e45f5a96d77..f03068e0cdc0d250e89d8ae59d4d8b0a09053604 100644 (file)
@@ -683,6 +683,15 @@ static bool translateInstruction(MCInst &mcInst,
   }
   
   mcInst.setOpcode(insn.instructionID);
+  // If when reading the prefix bytes we determined the overlapping 0xf2 or 0xf3
+  // prefix bytes should be disassembled as xrelease and xacquire then set the
+  // opcode to those instead of the rep and repne opcodes.
+  if (insn.xAcquireRelease) {
+    if(mcInst.getOpcode() == X86::REP_PREFIX)
+      mcInst.setOpcode(X86::XRELEASE_PREFIX);
+    else if(mcInst.getOpcode() == X86::REPNE_PREFIX)
+      mcInst.setOpcode(X86::XACQUIRE_PREFIX);
+  }
   
   int index;
   
index e40edba6d689e94e84a4b378fed56fffd845512e..55ab8ebe7b0b3ce7c6f4d0d7a37a274807f80dfb 100644 (file)
@@ -328,6 +328,27 @@ static int readPrefixes(struct InternalInstruction* insn) {
         break;
       if (lookAtByte(insn, &nextByte))
         return -1;
+      /*
+       * If the byte is 0xf2 or 0xf3, and any of the following conditions are
+       * met:
+       * - it is followed by a LOCK (0xf0) prefix
+       * - it is followed by an xchg instruction
+       * then it should be disassembled as a xacquire/xrelease not repne/rep.
+       */
+      if ((byte == 0xf2 || byte == 0xf3) &&
+          ((nextByte == 0xf0) |
+          ((nextByte & 0xfe) == 0x86 || (nextByte & 0xf8) == 0x90)))
+        insn->xAcquireRelease = TRUE;
+      /*
+       * Also if the byte is 0xf3, and the following condition is met:
+       * - it is followed by a "mov mem, reg" (opcode 0x88/0x89) or
+       *                       "mov mem, imm" (opcode 0xc6/0xc7) instructions.
+       * then it should be disassembled as an xrelease not rep.
+       */
+      if (byte == 0xf3 &&
+          (nextByte == 0x88 || nextByte == 0x89 ||
+           nextByte == 0xc6 || nextByte == 0xc7))
+        insn->xAcquireRelease = TRUE;
       if (insn->mode == MODE_64BIT && (nextByte & 0xf0) == 0x40) {
         if (consumeByte(insn, &nextByte))
           return -1;
index 407ead3cafa9946af389456d29409e746002522d..04a0dc038bcd3764a2cf579a80aec26d82c4346e 100644 (file)
@@ -457,6 +457,8 @@ struct InternalInstruction {
   uint64_t necessaryPrefixLocation;
   /* The segment override type */
   SegmentOverride segmentOverride;
+  /* 1 if the prefix byte, 0xf2 or 0xf3 is xacquire or xrelease */
+  BOOL xAcquireRelease;
 
   /* Sizes of various critical pieces of data, in bytes */
   uint8_t registerSize;
index 9827a1809f1b7c09439a6925c9a14f4296ff2b52..d51f0a1c9266a393eaec94159562f6d6685a8f72 100644 (file)
 # CHECK: repne
 # CHECK-NEXT: movb  $0, (%rax)
 0xf2 0xc6 0x0 0x0
-# CHECK: rep
+
+# rdar://11019859 Support 2013 Haswell RTM instructions and HLE prefixes
+# CHECK: xrelease
 # CHECK-NEXT: lock
 # CHECK-NEXT: incl   (%rax)
 0xf3 0xf0 0xff 0x00
+
+# CHECK: xrelease
+# CHECK-NEXT: xchgl %ebx, %eax
+0xf3 0x93
+# CHECK: xrelease
+# CHECK-NEXT: xchgl %ebx, (%rax)
+0xf3 0x87 0x18
+# CHECK: xrelease
+# CHECK-NEXT: movb %al, (%rbx)
+0xf3 0x88 0x03
+# CHECK: xrelease
+# CHECK-NEXT: movl %eax, (%rbx)
+0xf3 0x89 0x03
+# CHECK: xrelease
+# CHECK-NEXT: movb $1, (%rbx)
+0xf3 0xc6 0x03 0x01
+# CHECK: xrelease
+# CHECK-NEXT: movl $1, (%rbx)
+0xf3 0xc7 0x03 0x01 0x00 0x00 0x00
+
+# CHECK: xacquire
+# CHECK-NEXT: xchgl %ebx, %eax
+0xf2 0x93
+# CHECK: xacquire
+# CHECK-NEXT: xchgl %ebx, (%rax)
+0xf2 0x87 0x18