From 2b6fdd5413ea44bbcbb8f0c2f7a737d1e9283abb Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Sat, 5 Aug 2017 00:10:43 +0000 Subject: [PATCH] [X86] Teach fastisel to select calls to dllimport functions Summary: Direct calls to dllimport functions are very common Windows. We should add them to the -O0 fast path. Reviewers: rafael Subscribers: llvm-commits, hiraditya Differential Revision: https://reviews.llvm.org/D36197 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@310152 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/X86/X86FastISel.cpp | 22 ++++++++++++++-------- lib/Target/X86/X86Subtarget.cpp | 7 ++++++- test/CodeGen/X86/dllimport-x86_64.ll | 5 ++--- test/CodeGen/X86/dllimport.ll | 5 ++--- test/CodeGen/X86/fast-isel-call-cleanup.ll | 19 +++++++++++++++++++ test/CodeGen/X86/fast-isel-x86.ll | 19 ------------------- 6 files changed, 43 insertions(+), 34 deletions(-) create mode 100644 test/CodeGen/X86/fast-isel-call-cleanup.ll diff --git a/lib/Target/X86/X86FastISel.cpp b/lib/Target/X86/X86FastISel.cpp index 527e5d568ac..5c1303da83d 100644 --- a/lib/Target/X86/X86FastISel.cpp +++ b/lib/Target/X86/X86FastISel.cpp @@ -1077,10 +1077,6 @@ bool X86FastISel::X86SelectCallAddress(const Value *V, X86AddressMode &AM) { (AM.Base.Reg != 0 || AM.IndexReg != 0)) return false; - // Can't handle DLL Import. - if (GV->hasDLLImportStorageClass()) - return false; - // Can't handle TLS. if (const GlobalVariable *GVar = dyn_cast(GV)) if (GVar->isThreadLocal()) @@ -1089,8 +1085,9 @@ bool X86FastISel::X86SelectCallAddress(const Value *V, X86AddressMode &AM) { // Okay, we've committed to selecting this global. Set up the basic address. AM.GV = GV; - // No ABI requires an extra load for anything other than DLLImport, which - // we rejected above. Return a direct reference to the global. + // Return a direct reference to the global. Fastisel can handle calls to + // functions that require loads, such as dllimport and nonlazybind + // functions. if (Subtarget->isPICStyleRIPRel()) { // Use rip-relative addressing if we can. Above we verified that the // base and index registers are unused. @@ -3455,19 +3452,28 @@ bool X86FastISel::fastLowerCall(CallLoweringInfo &CLI) { } else { // Direct call. assert(GV && "Not a direct call"); - unsigned CallOpc = Is64Bit ? X86::CALL64pcrel32 : X86::CALLpcrel32; - // See if we need any target-specific flags on the GV operand. unsigned char OpFlags = Subtarget->classifyGlobalFunctionReference(GV); // Ignore NonLazyBind attribute in FastISel if (OpFlags == X86II::MO_GOTPCREL) OpFlags = 0; + // This will be a direct call, or an indirect call through memory for + // NonLazyBind calls or dllimport calls. + bool NeedLoad = OpFlags == X86II::MO_DLLIMPORT; + unsigned CallOpc = NeedLoad + ? (Is64Bit ? X86::CALL64m : X86::CALL32m) + : (Is64Bit ? X86::CALL64pcrel32 : X86::CALLpcrel32); + MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(CallOpc)); + if (NeedLoad) + MIB.addReg(Is64Bit ? X86::RIP : 0).addImm(1).addReg(0); if (Symbol) MIB.addSym(Symbol, OpFlags); else MIB.addGlobalAddress(GV, 0, OpFlags); + if (NeedLoad) + MIB.addReg(0); } // Add a register mask operand representing the call-preserved registers. diff --git a/lib/Target/X86/X86Subtarget.cpp b/lib/Target/X86/X86Subtarget.cpp index 33c6378f785..bada96df869 100644 --- a/lib/Target/X86/X86Subtarget.cpp +++ b/lib/Target/X86/X86Subtarget.cpp @@ -147,7 +147,12 @@ X86Subtarget::classifyGlobalFunctionReference(const GlobalValue *GV, if (TM.shouldAssumeDSOLocal(M, GV)) return X86II::MO_NO_FLAG; - assert(!isTargetCOFF()); + if (isTargetCOFF()) { + assert(GV->hasDLLImportStorageClass() && + "shouldAssumeDSOLocal gave inconsistent answer"); + return X86II::MO_DLLIMPORT; + } + const Function *F = dyn_cast_or_null(GV); if (isTargetELF()) { diff --git a/test/CodeGen/X86/dllimport-x86_64.ll b/test/CodeGen/X86/dllimport-x86_64.ll index 7ee6b4323d1..205736ada51 100644 --- a/test/CodeGen/X86/dllimport-x86_64.ll +++ b/test/CodeGen/X86/dllimport-x86_64.ll @@ -1,7 +1,8 @@ ; RUN: llc -mtriple x86_64-pc-win32 < %s | FileCheck %s ; RUN: llc -mtriple x86_64-pc-mingw32 < %s | FileCheck %s ; -; RUN: llc -mtriple x86_64-pc-mingw32 -O0 < %s | FileCheck %s -check-prefix=FAST +; RUN: llc -mtriple x86_64-pc-mingw32 -O0 < %s | FileCheck %s +; RUN: llc -mtriple x86_64-pc-windows-msvc -O0 < %s | FileCheck %s ; PR6275 ; ; RUN: opt -mtriple x86_64-pc-win32 -O3 -S < %s | FileCheck %s -check-prefix=OPT @@ -23,8 +24,6 @@ declare void @dummy(...) define void @use() nounwind { ; CHECK: callq *__imp_fun(%rip) -; FAST: movq __imp_fun(%rip), [[R:%[a-z]{3}]] -; FAST-NEXT: callq *[[R]] call void @fun() ; CHECK: callq *__imp_inline1(%rip) diff --git a/test/CodeGen/X86/dllimport.ll b/test/CodeGen/X86/dllimport.ll index 34faaeb6fed..7f90aa7e313 100644 --- a/test/CodeGen/X86/dllimport.ll +++ b/test/CodeGen/X86/dllimport.ll @@ -1,7 +1,8 @@ ; RUN: llc -mtriple i386-pc-win32 < %s | FileCheck %s ; RUN: llc -mtriple i386-pc-mingw32 < %s | FileCheck %s ; -; RUN: llc -mtriple i386-pc-mingw32 -O0 < %s | FileCheck %s -check-prefix=FAST +; RUN: llc -mtriple i386-pc-mingw32 -O0 < %s | FileCheck %s +; RUN: llc -mtriple i386-pc-windows-msvc -O0 < %s | FileCheck %s ; PR6275 ; ; RUN: opt -mtriple i386-pc-win32 -O3 -S < %s | FileCheck %s -check-prefix=OPT @@ -27,8 +28,6 @@ declare void @dummy(...) define void @use() nounwind { ; CHECK: calll *__imp__fun -; FAST: movl __imp__fun, [[R:%[a-z]{3}]] -; FAST-NEXT: calll *[[R]] call void @fun() ; CHECK: calll *__imp__inline1 diff --git a/test/CodeGen/X86/fast-isel-call-cleanup.ll b/test/CodeGen/X86/fast-isel-call-cleanup.ll new file mode 100644 index 00000000000..5289c905dc0 --- /dev/null +++ b/test/CodeGen/X86/fast-isel-call-cleanup.ll @@ -0,0 +1,19 @@ +; RUN: llc -fast-isel -O0 -code-model=large -mcpu=generic -mtriple=x86_64-apple-darwin10 -relocation-model=pic < %s | FileCheck %s + +; Check that fast-isel cleans up when it fails to lower a call instruction. +define void @fastiselcall() { +entry: + %call = call i32 @targetfn(i32 42) + ret void +; CHECK-LABEL: test5: +; Local value area is still there: +; CHECK: movl $42, {{%[a-z]+}} +; Fast-ISel's arg mov is not here: +; CHECK-NOT: movl $42, (%esp) +; SDag-ISel's arg mov: +; CHECK: movabsq $_targetfn, %[[REG:[^ ]*]] +; CHECK: movl $42, %edi +; CHECK: callq *%[[REG]] + +} +declare i32 @targetfn(i32) diff --git a/test/CodeGen/X86/fast-isel-x86.ll b/test/CodeGen/X86/fast-isel-x86.ll index aa6d9b7cf05..3923cf9bb92 100644 --- a/test/CodeGen/X86/fast-isel-x86.ll +++ b/test/CodeGen/X86/fast-isel-x86.ll @@ -88,22 +88,3 @@ entry: ; CHECK: addl $28 } declare fastcc void @test4fastccsret(%struct.a* sret) - - -; Check that fast-isel cleans up when it fails to lower a call instruction. -define void @test5() { -entry: - %call = call i32 @test5dllimport(i32 42) - ret void -; CHECK-LABEL: test5: -; Local value area is still there: -; CHECK: movl $42, {{%[a-z]+}} -; Fast-ISel's arg push is not here: -; CHECK-NOT: movl $42, (%esp) -; SDag-ISel's arg push: -; CHECK: movl %esp, [[REGISTER:%[a-z]+]] -; CHECK: movl $42, ([[REGISTER]]) -; CHECK: movl L_test5dllimport$non_lazy_ptr-L8$pb(%eax), %eax - -} -declare dllimport i32 @test5dllimport(i32) -- 2.11.0