From 5b37c181291210bedfbb7a6af5d51229f3652ef0 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 1 Aug 2014 20:21:24 +0000 Subject: [PATCH] MS inline asm: Use memory constraints for functions instead of registers This is consistent with how we parse them in a standalone .s file, and inline assembly shouldn't differ. This fixes errors about requiring more registers than available in cases like this: void f(); void __declspec(naked) g() { __asm pusha __asm call f __asm popa __asm ret } There are no registers available to pass the address of 'f' into the asm blob. The asm should now directly call 'f'. Tests will land in Clang shortly. llvm-svn: 214550 --- llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp | 30 ++++++++++++++++++-------- llvm/test/CodeGen/X86/ms-inline-asm.ll | 11 +++++++++- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp index bc13ed6..e504f27 100644 --- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -731,6 +731,13 @@ private: (X86::Mode64Bit | X86::Mode32Bit | X86::Mode16Bit))); } + unsigned getPointerWidth() { + if (is16BitMode()) return 16; + if (is32BitMode()) return 32; + if (is64BitMode()) return 64; + llvm_unreachable("invalid mode"); + } + bool isParsingIntelSyntax() { return getParser().getAssemblerDialect(); } @@ -982,15 +989,20 @@ std::unique_ptr X86AsmParser::CreateMemForInlineAsm( unsigned SegReg, const MCExpr *Disp, unsigned BaseReg, unsigned IndexReg, unsigned Scale, SMLoc Start, SMLoc End, unsigned Size, StringRef Identifier, InlineAsmIdentifierInfo &Info) { - // If this is not a VarDecl then assume it is a FuncDecl or some other label - // reference. We need an 'r' constraint here, so we need to create register - // operand to ensure proper matching. Just pick a GPR based on the size of - // a pointer. - if (isa(Disp) && !Info.IsVarDecl) { - unsigned RegNo = - is64BitMode() ? X86::RBX : (is32BitMode() ? X86::EBX : X86::BX); - return X86Operand::CreateReg(RegNo, Start, End, /*AddressOf=*/true, - SMLoc(), Identifier, Info.OpDecl); + // If we found a decl other than a VarDecl, then assume it is a FuncDecl or + // some other label reference. + if (isa(Disp) && Info.OpDecl && !Info.IsVarDecl) { + // Insert an explicit size if the user didn't have one. + if (!Size) { + Size = getPointerWidth(); + InstInfo->AsmRewrites->push_back(AsmRewrite(AOK_SizeDirective, Start, + /*Len=*/0, Size)); + } + + // Create an absolute memory reference in order to match against + // instructions taking a PC relative operand. + return X86Operand::CreateMem(Disp, Start, End, Size, Identifier, + Info.OpDecl); } // We either have a direct symbol reference, or an offset from a symbol. The diff --git a/llvm/test/CodeGen/X86/ms-inline-asm.ll b/llvm/test/CodeGen/X86/ms-inline-asm.ll index 6910515..51f5d5f 100644 --- a/llvm/test/CodeGen/X86/ms-inline-asm.ll +++ b/llvm/test/CodeGen/X86/ms-inline-asm.ll @@ -110,7 +110,7 @@ define i32 @t31() { entry: %val = alloca i32, align 64 store i32 -1, i32* %val, align 64 - call void asm sideeffect inteldialect "mov dword ptr $0, esp", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* %val) #1 + call void asm sideeffect inteldialect "mov dword ptr $0, esp", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* %val) %sp = load i32* %val, align 64 ret i32 %sp ; CHECK-LABEL: t31: @@ -125,3 +125,12 @@ entry: ; CHECK: movl (%esp), %eax ; CHECK: ret } + +declare void @other_func() + +define void @naked() #0 { + call void asm sideeffect inteldialect "call dword ptr $0", "*m,~{eax},~{ebx},~{ecx},~{edx},~{edi},~{esi},~{esp},~{ebp},~{dirflag},~{fpsr},~{flags}"(void()* @other_func) + unreachable +} + +attributes #0 = { naked } -- 2.7.4