[X86][MC] Fix parsing Intel syntax indirect branch with symbol only
authorAlvin Wong <alvin@alvinhc.com>
Mon, 1 May 2023 11:03:37 +0000 (19:03 +0800)
committerAlvin Wong <alvin@alvinhc.com>
Mon, 8 May 2023 16:07:40 +0000 (00:07 +0800)
Clang on Windows targets often requires indirect calls through the
import address table (IAT), and also .refptr stubs for MinGW target.
On 32-bit this generates assembly in the form of
`call dword ptr [__imp__func]`, which MC had failed to handle correctly.
64-bit targets are not affected because rip-relative addressing is used.

Reported on: https://github.com/llvm/llvm-project/issues/62010

Depends on D149695, D149920

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

clang/test/CodeGen/ms-inline-asm-functions.c
llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
llvm/test/MC/X86/intel-syntax-branch.s [new file with mode: 0644]

index 26eaf14..57abcc2 100644 (file)
@@ -24,10 +24,9 @@ int foo(void) {
   __asm call kimport;
   // CHECK:     calll   *({{.*}})
 
-  // Broken case: Call through a global function pointer.
+  // Call through a global function pointer.
   __asm call kptr;
-  // CHECK:     calll   _kptr
-  // CHECK-FIXME: calll   *_kptr
+  // CHECK:     calll   *_kptr
 }
 
 int bar(void) {
index 6799234..2647117 100644 (file)
@@ -433,6 +433,7 @@ private:
     InlineAsmIdentifierInfo Info;
     short BracCount = 0;
     bool MemExpr = false;
+    bool BracketUsed = false;
     bool OffsetOperator = false;
     bool AttachToOperandIdx = false;
     bool IsPIC = false;
@@ -455,6 +456,7 @@ private:
     void addImm(int64_t imm) { Imm += imm; }
     short getBracCount() const { return BracCount; }
     bool isMemExpr() const { return MemExpr; }
+    bool isBracketUsed() const { return BracketUsed; }
     bool isOffsetOperator() const { return OffsetOperator; }
     SMLoc getOffsetLoc() const { return OffsetOperatorLoc; }
     unsigned getBaseReg() const { return BaseReg; }
@@ -955,6 +957,7 @@ private:
         break;
       }
       MemExpr = true;
+      BracketUsed = true;
       BracCount++;
       return false;
     }
@@ -2628,9 +2631,9 @@ bool X86AsmParser::parseIntelOperand(OperandVector &Operands, StringRef Name) {
   unsigned DefaultBaseReg = X86::NoRegister;
   bool MaybeDirectBranchDest = true;
 
+  bool IsUnconditionalBranch =
+      Name.equals_insensitive("jmp") || Name.equals_insensitive("call");
   if (Parser.isParsingMasm()) {
-    bool IsUnconditionalBranch =
-        Name.equals_insensitive("jmp") || Name.equals_insensitive("call");
     if (is64BitMode() && SM.getElementSize() > 0) {
       DefaultBaseReg = X86::RIP;
     }
@@ -2652,6 +2655,9 @@ bool X86AsmParser::parseIntelOperand(OperandVector &Operands, StringRef Name) {
         }
       }
     }
+  } else if (IsUnconditionalBranch) {
+    if (PtrInOperand || SM.isBracketUsed())
+      MaybeDirectBranchDest = false;
   }
 
   if ((BaseReg || IndexReg || RegNo || DefaultBaseReg != X86::NoRegister))
diff --git a/llvm/test/MC/X86/intel-syntax-branch.s b/llvm/test/MC/X86/intel-syntax-branch.s
new file mode 100644 (file)
index 0000000..22b9156
--- /dev/null
@@ -0,0 +1,71 @@
+// RUN: llvm-mc -triple i686-unknown-unknown -x86-asm-syntax=intel %s | FileCheck %s --check-prefixes=CHECK-32,CHECK
+// RUN: llvm-mc -triple x86_64-unknown-unknown --defsym X64=1 -x86-asm-syntax=intel %s | FileCheck %s --check-prefixes=CHECK-64,CHECK
+
+// RUN: not llvm-mc -triple i686-unknown-unknown --defsym ERR=1 -x86-asm-syntax=intel %s 2>&1 | FileCheck %s --check-prefixes=ERR-32
+
+t0:
+call direct_branch
+jmp direct_branch
+// CHECK-LABEL: t0:
+// CHECK-64: callq direct_branch
+// CHECK-32: calll direct_branch
+// CHECK:    jmp direct_branch
+
+t1:
+call [fn_ref]
+jmp [fn_ref]
+// CHECK-LABEL: t1:
+// CHECK-64: callq *fn_ref
+// CHECK-64: jmpq *fn_ref
+// CHECK-32: calll *fn_ref
+// CHECK-32: jmpl *fn_ref
+
+.ifdef X64
+
+  t2:
+  call qword ptr [fn_ref]
+  jmp qword ptr [fn_ref]
+  // CHECK-64-LABEL: t2:
+  // CHECK-64: callq *fn_ref
+  // CHECK-64: jmpq *fn_ref
+
+  t3:
+  call qword ptr [rip + fn_ref]
+  jmp qword ptr [rip + fn_ref]
+  // CHECK-64-LABEL: t3:
+  // CHECK-64: callq *fn_ref(%rip)
+  // CHECK-64: jmpq *fn_ref(%rip)
+
+.else
+
+  t4:
+  call dword ptr [fn_ref]
+  jmp dword ptr [fn_ref]
+  // CHECK-32-LABEL: t4:
+  // CHECK-32: calll *fn_ref
+  // CHECK-32: jmpl *fn_ref
+
+  t5:
+  call dword ptr fn_ref
+  jmp dword ptr fn_ref
+  // CHECK-32-LABEL: t5:
+  // CHECK-32: calll *fn_ref
+  // CHECK-32: jmpl *fn_ref
+
+  t6:
+  call dword ptr [offset fn_ref]
+  jmp dword ptr [offset fn_ref]
+  // CHECK-32-LABEL: t6:
+  // CHECK-32: calll *fn_ref
+  // CHECK-32: jmpl *fn_ref
+
+.ifdef ERR
+
+  call offset fn_ref
+  // ERR-32: {{.*}}.s:[[#@LINE-1]]:3: error: invalid operand for instruction
+  jmp offset fn_ref
+  // ERR-32: {{.*}}.s:[[#@LINE-1]]:3: error: invalid operand for instruction
+
+.endif
+
+.endif