[clang] 8afd831 - ms inline asm: recognize case-insensitive JMP and CALL as TargetLowering::C_Address

Fangrui Song via cfe-commits cfe-commits at lists.llvm.org
Fri May 5 15:32:38 PDT 2023


Author: Fangrui Song
Date: 2023-05-05T15:32:32-07:00
New Revision: 8afd831b456a46677e638cdf00dd649fbd5ca0a1

URL: https://github.com/llvm/llvm-project/commit/8afd831b456a46677e638cdf00dd649fbd5ca0a1
DIFF: https://github.com/llvm/llvm-project/commit/8afd831b456a46677e638cdf00dd649fbd5ca0a1.diff

LOG: ms inline asm: recognize case-insensitive JMP and CALL as TargetLowering::C_Address

In a `__asm` block, a symbol reference is usually a memory constraint
(indirect TargetLowering::C_Memory) [LOOP]. CALL and JUMP instructions are special
that `__asm call k` can be an address constraint, if `k` is a function.

Clang always gives us indirect TargetLowering::C_Memory and need to convert it
to direct TargetLowering::C_Address. D133914 implements this conversion, but
does not consider JMP or case-insensitive CALL. This patch implements the missing
cases, so that `__asm jmp k` (`jmp ${0:P}`) will correctly lower to `jmp _k`
instead of `jmp dword ptr [_k]`.

(`__asm call k` lowered to `call dword ptr ${0:P}` and is fixed by D149695 to
lower to `call ${0:P}` instead.)

[LOOP]: Some instructions like LOOP{,E,NE} and Jcc always use an address
constraint (`loop _k` instead of `loop dword ptr [_k]`).

After this patch and D149579, all the following cases will be correct.
```
int k(int);
int (*kptr)(int);
...
__asm call k; // correct without this patch
__asm CALL k; // correct, but needs this patch to be compatible with D149579
__asm jmp k;  // correct, but needs this patch to be compatible with D149579
__asm call kptr; // will be fixed by D149579.  "Broken case" in clang/test/CodeGen/ms-inline-asm-functions.c
__asm jmp kptr;  // will be fixed by this patch and D149579
```

Reviewed By: pengfei

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

Added: 
    

Modified: 
    clang/test/CodeGen/ms-inline-asm-functions.c
    llvm/include/llvm/CodeGen/TargetLowering.h
    llvm/lib/Target/X86/X86ISelLowering.cpp
    llvm/test/CodeGen/X86/inline-asm-function-call-pic.ll

Removed: 
    


################################################################################
diff  --git a/clang/test/CodeGen/ms-inline-asm-functions.c b/clang/test/CodeGen/ms-inline-asm-functions.c
index ad6a385279dc..26eaf144adf2 100644
--- a/clang/test/CodeGen/ms-inline-asm-functions.c
+++ b/clang/test/CodeGen/ms-inline-asm-functions.c
@@ -32,8 +32,20 @@ int foo(void) {
 
 int bar(void) {
   // CHECK-LABEL: _bar:
-  __asm jmp k;
-  // CHECK:     jmp     _k
+  __asm {
+    jmp k
+    ja k
+    JAE k
+    LOOP k
+    loope k
+    loopne k
+  };
+  // CHECK:      jmp     _k
+  // CHECK-NEXT: ja      _k
+  // CHECK-NEXT: jae     _k
+  // CHECK-NEXT: loop    _k
+  // CHECK-NEXT: loope   _k
+  // CHECK-NEXT: loopne  _k
 }
 
 int baz(void) {

diff  --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 4c5e18192ea2..355091146d24 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -3624,15 +3624,13 @@ class TargetLowering : public TargetLoweringBase {
   /// legal.  It is frequently not legal in PIC relocation models.
   virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const;
 
-  /// Return true if the operand with index OpNo corresponding to a target
-  /// branch, for example, in following case
+  /// On x86, return true if the operand with index OpNo is a CALL or JUMP
+  /// instruction, which can use either a memory constraint or an address
+  /// constraint. -fasm-blocks "__asm call foo" lowers to
+  /// call void asm sideeffect inteldialect "call ${0:P}", "*m..."
   ///
-  /// call void asm "lea r8, $0\0A\09call qword ptr ${1:P}\0A\09ret",
-  ///               "*m,*m,~{r8},~{dirflag},~{fpsr},~{flags}"
-  ///                ([9 x i32]* @Arr), void (...)* @sincos_asm)
-  ///
-  /// the operand $1 (sincos_asm) is target branch in inline asm, but the
-  /// operand $0 (Arr) is not.
+  /// This function is used by a hack to choose the address constraint,
+  /// lowering to a direct call.
   virtual bool
   isInlineAsmTargetBranch(const SmallVectorImpl<StringRef> &AsmStrs,
                           unsigned OpNo) const {

diff  --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 2c7dce0d3612..19a9b402c930 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -33944,12 +33944,9 @@ static StringRef getInstrStrFromOpNo(const SmallVectorImpl<StringRef> &AsmStrs,
     // "call dword ptr "
     auto TmpStr = AsmStr.substr(0, I);
     I = TmpStr.rfind(':');
-    if (I == StringRef::npos)
-      return TmpStr;
-
-    assert(I < TmpStr.size() && "Unexpected inline asm string!");
-    auto Asm = TmpStr.drop_front(I + 1);
-    return Asm;
+    if (I != StringRef::npos)
+      TmpStr = TmpStr.substr(I + 1);
+    return TmpStr.take_while(llvm::isAlpha);
   }
 
   return StringRef();
@@ -33957,12 +33954,13 @@ static StringRef getInstrStrFromOpNo(const SmallVectorImpl<StringRef> &AsmStrs,
 
 bool X86TargetLowering::isInlineAsmTargetBranch(
     const SmallVectorImpl<StringRef> &AsmStrs, unsigned OpNo) const {
-  StringRef InstrStr = getInstrStrFromOpNo(AsmStrs, OpNo);
-
-  if (InstrStr.contains("call"))
-    return true;
-
-  return false;
+  // In a __asm block, __asm inst foo where inst is CALL or JMP should be
+  // changed from indirect TargetLowering::C_Memory to direct
+  // TargetLowering::C_Address.
+  // We don't need to special case LOOP* and Jcc, which cannot target a memory
+  // location.
+  StringRef Inst = getInstrStrFromOpNo(AsmStrs, OpNo);
+  return Inst.equals_insensitive("call") || Inst.equals_insensitive("jmp");
 }
 
 /// Provide custom lowering hooks for some operations.

diff  --git a/llvm/test/CodeGen/X86/inline-asm-function-call-pic.ll b/llvm/test/CodeGen/X86/inline-asm-function-call-pic.ll
index 8c82b3670af5..3c98eead8d18 100644
--- a/llvm/test/CodeGen/X86/inline-asm-function-call-pic.ll
+++ b/llvm/test/CodeGen/X86/inline-asm-function-call-pic.ll
@@ -15,6 +15,7 @@
 ;   __asm {
 ;           call static_func
 ;           call extern_func
+;           jmp extern_func
 ;           shr eax, 0
 ;           shr ebx, 0
 ;           shr ecx, 0
@@ -40,6 +41,7 @@ define void @func() local_unnamed_addr #0 {
 ; CHECK-EMPTY:
 ; CHECK-NEXT:    calll static_func
 ; CHECK-NEXT:    calll extern_func at PLT
+; CHECK-NEXT:    jmp extern_func at PLT
 ; CHECK-NEXT:    shrl $0, %eax
 ; CHECK-NEXT:    shrl $0, %ebx
 ; CHECK-NEXT:    shrl $0, %ecx
@@ -52,7 +54,8 @@ define void @func() local_unnamed_addr #0 {
 ; CHECK-NEXT:    #NO_APP
 entry:
   %call = tail call i32 @static_func()
-  tail call void asm sideeffect inteldialect "call dword ptr ${0:P}\0A\09call dword ptr ${1:P}\0A\09shr eax, $$0\0A\09shr ebx, $$0\0A\09shr ecx, $$0\0A\09shr edx, $$0\0A\09shr edi, $$0\0A\09shr esi, $$0\0A\09shr ebp, $$0\0A\09shr esp, $$0", "*m,*m,~{eax},~{ebp},~{ebx},~{ecx},~{edi},~{edx},~{flags},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"(ptr nonnull elementtype(i32 (...)) @static_func, ptr nonnull elementtype(i32 (...)) @extern_func) #0
+;; We test call, CALL, and jmp.
+  tail call void asm sideeffect inteldialect "call ${0:P}\0A\09CALL ${1:P}\0A\09jmp ${1:P}\0A\09shr eax, $$0\0A\09shr ebx, $$0\0A\09shr ecx, $$0\0A\09shr edx, $$0\0A\09shr edi, $$0\0A\09shr esi, $$0\0A\09shr ebp, $$0\0A\09shr esp, $$0", "*m,*m,~{eax},~{ebp},~{ebx},~{ecx},~{edi},~{edx},~{flags},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"(ptr nonnull elementtype(i32 (...)) @static_func, ptr nonnull elementtype(i32 (...)) @extern_func) #0
   ret void
 }
 


        


More information about the cfe-commits mailing list