[X86] Add support for {disp32} to control size of jmp and jcc instructions in the...
authorCraig Topper <craig.topper@intel.com>
Tue, 28 Jul 2020 04:11:48 +0000 (21:11 -0700)
committerCraig Topper <craig.topper@intel.com>
Tue, 28 Jul 2020 04:11:48 +0000 (21:11 -0700)
By default we pick a 1 byte displacement and let relaxation enlarge it if necessary. The GNU assembler supports a pseudo prefix to basically pre-relax the instruction the larger size.

I plan to add {disp8} and {disp32} support for memory operands in another patch which is why I've included the parsing code and enum for {disp8} pseudo prefix as well.

Reviewed By: echristo

Differential Revision: https://reviews.llvm.org/D84709

llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
llvm/test/MC/X86/x86-16.s
llvm/test/MC/X86/x86-32.s

index a3014b2..bb9919a 100644 (file)
@@ -87,6 +87,14 @@ class X86AsmParser : public MCTargetAsmParser {
 
   VEXEncoding ForcedVEXEncoding = VEXEncoding_Default;
 
+  enum DispEncoding {
+    DispEncoding_Default,
+    DispEncoding_Disp8,
+    DispEncoding_Disp32,
+  };
+
+  DispEncoding ForcedDispEncoding = DispEncoding_Default;
+
 private:
   SMLoc consumeToken() {
     MCAsmParser &Parser = getParser();
@@ -2592,6 +2600,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
 
   // Reset the forced VEX encoding.
   ForcedVEXEncoding = VEXEncoding_Default;
+  ForcedDispEncoding = DispEncoding_Default;
 
   // Parse pseudo prefixes.
   while (1) {
@@ -2610,6 +2619,10 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
         ForcedVEXEncoding = VEXEncoding_VEX3;
       else if (Prefix == "evex")
         ForcedVEXEncoding = VEXEncoding_EVEX;
+      else if (Prefix == "disp8")
+        ForcedDispEncoding = DispEncoding_Disp8;
+      else if (Prefix == "disp32")
+        ForcedDispEncoding = DispEncoding_Disp32;
       else
         return Error(NameLoc, "unknown prefix");
 
@@ -3118,6 +3131,26 @@ bool X86AsmParser::processInstruction(MCInst &Inst, const OperandVector &Ops) {
 
   switch (Inst.getOpcode()) {
   default: return false;
+  case X86::JMP_1:
+    // {disp32} forces a larger displacement as if the instruction was relaxed.
+    // NOTE: 16-bit mode uses 16-bit displacement even though it says {disp32}.
+    // This matches GNU assembler.
+    if (ForcedDispEncoding == DispEncoding_Disp32) {
+      Inst.setOpcode(is16BitMode() ? X86::JMP_2 : X86::JMP_4);
+      return true;
+    }
+
+    return false;
+  case X86::JCC_1:
+    // {disp32} forces a larger displacement as if the instruction was relaxed.
+    // NOTE: 16-bit mode uses 16-bit displacement even though it says {disp32}.
+    // This matches GNU assembler.
+    if (ForcedDispEncoding == DispEncoding_Disp32) {
+      Inst.setOpcode(is16BitMode() ? X86::JCC_2 : X86::JCC_4);
+      return true;
+    }
+
+    return false;
   case X86::VMOVZPQILo2PQIrr:
   case X86::VMOVAPDrr:
   case X86::VMOVAPDYrr:
index ed35409..f92164e 100644 (file)
@@ -1045,3 +1045,14 @@ xsusldtrk
 // CHECK: xresldtrk
 // CHECK: encoding: [0xf2,0x0f,0x01,0xe9]
 xresldtrk
+
+// CHECK: jmp foo
+// CHECK:  encoding: [0xe9,A,A]
+// CHECK:  fixup A - offset: 1, value: foo-2, kind: FK_PCRel_2
+{disp32} jmp foo
+foo:
+
+// CHECK: je foo
+// CHECK:  encoding: [0x0f,0x84,A,A]
+// CHECK:  fixup A - offset: 2, value: foo-2, kind: FK_PCRel_2
+{disp32} je foo
index fdd3c53..256d835 100644 (file)
@@ -1109,3 +1109,14 @@ ptwritel 0xdeadbeef(%ebx,%ecx,8)
 // CHECK: ptwritel %eax
 // CHECK:  encoding: [0xf3,0x0f,0xae,0xe0]
 ptwritel %eax
+
+// CHECK: jmp foo
+// CHECK:  encoding: [0xe9,A,A,A,A]
+// CHECK:  fixup A - offset: 1, value: foo-4, kind: FK_PCRel_4
+{disp32} jmp foo
+foo:
+
+// CHECK: je foo
+// CHECK:  encoding: [0x0f,0x84,A,A,A,A]
+// CHECK:  fixup A - offset: 2, value: foo-4, kind: FK_PCRel_4
+{disp32} je foo