[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