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@PLT +; CHECK-NEXT: jmp extern_func@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 } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits