Index: llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h +++ llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h @@ -113,10 +113,9 @@ /// True if debugging information is available in this module. bool DbgInfoAvailable; - /// True if this module calls VarArg function with floating-point arguments. - /// This is used to emit an undefined reference to _fltused on Windows - /// targets. - bool UsesVAFloatArgument; + /// True if this module is being built for windows/msvc, and uses floating + /// point. This is used to emit an undefined reference to _fltused. + bool UsesMSVCFloatingPoint; /// True if the module calls the __morestack function indirectly, as is /// required under the large code model on x86. This is used to emit @@ -186,13 +185,9 @@ bool hasDebugInfo() const { return DbgInfoAvailable; } void setDebugInfoAvailability(bool avail) { DbgInfoAvailable = avail; } - bool usesVAFloatArgument() const { - return UsesVAFloatArgument; - } + bool usesMSVCFloatingPoint() const { return UsesMSVCFloatingPoint; } - void setUsesVAFloatArgument(bool b) { - UsesVAFloatArgument = b; - } + void setUsesMSVCFloatingPoint(bool b) { UsesMSVCFloatingPoint = b; } bool usesMorestackAddr() const { return UsesMorestackAddr; @@ -257,14 +252,6 @@ /// \} }; // End class MachineModuleInfo -//===- MMI building helpers -----------------------------------------------===// - -/// Determine if any floating-point values are being passed to this variadic -/// function, and set the MachineModuleInfo's usesVAFloatArgument flag if so. -/// This flag is used to emit an undefined reference to _fltused on Windows, -/// which will link in MSVCRT's floating-point support. -void computeUsesVAFloatArgument(const CallInst &I, MachineModuleInfo &MMI); - } // end namespace llvm #endif // LLVM_CODEGEN_MACHINEMODULEINFO_H Index: llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp +++ llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp @@ -205,7 +205,7 @@ bool MachineModuleInfo::doInitialization(Module &M) { ObjFileMMI = nullptr; CurCallSite = 0; - UsesVAFloatArgument = UsesMorestackAddr = false; + UsesMSVCFloatingPoint = UsesMorestackAddr = false; HasSplitStack = HasNosplitStack = false; AddrLabelSymbols = nullptr; TheModule = &M; @@ -327,22 +327,3 @@ FunctionPass *llvm::createFreeMachineFunctionPass() { return new FreeMachineFunction(); } - -//===- MMI building helpers -----------------------------------------------===// - -void llvm::computeUsesVAFloatArgument(const CallInst &I, - MachineModuleInfo &MMI) { - FunctionType *FT = - cast(I.getCalledValue()->getType()->getContainedType(0)); - if (FT->isVarArg() && !MMI.usesVAFloatArgument()) { - for (unsigned i = 0, e = I.getNumArgOperands(); i != e; ++i) { - Type *T = I.getArgOperand(i)->getType(); - for (auto i : post_order(T)) { - if (i->isFloatingPointTy()) { - MMI.setUsesVAFloatArgument(true); - return; - } - } - } - } -} Index: llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1303,9 +1303,6 @@ return true; } - MachineModuleInfo &MMI = FuncInfo.MF->getMMI(); - computeUsesVAFloatArgument(*Call, MMI); - // Handle intrinsic function calls. if (const auto *II = dyn_cast(Call)) return selectIntrinsicCall(II); Index: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -6987,9 +6987,6 @@ return; } - MachineModuleInfo &MMI = DAG.getMachineFunction().getMMI(); - computeUsesVAFloatArgument(I, MMI); - const char *RenameFn = nullptr; if (Function *F = I.getCalledFunction()) { if (F->isDeclaration()) { Index: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -41,6 +41,7 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachinePassRegistry.h" #include "llvm/CodeGen/MachineRegisterInfo.h" @@ -62,6 +63,7 @@ #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/InlineAsm.h" +#include "llvm/IR/InstIterator.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" @@ -378,6 +380,30 @@ } } +static void computeUsesMSVCFloatingPoint(const Triple &TT, const Function &F, + MachineModuleInfo &MMI) { + // Only needed for MSVC + if (!TT.isKnownWindowsMSVCEnvironment()) + return; + + // If it's already set, nothing to do. + if (MMI.usesMSVCFloatingPoint()) + return; + + for (const Instruction &I : instructions(F)) { + if (I.getType()->isFPOrFPVectorTy()) { + MMI.setUsesMSVCFloatingPoint(true); + return; + } + for (const auto &Op : I.operands()) { + if (Op->getType()->isFPOrFPVectorTy()) { + MMI.setUsesMSVCFloatingPoint(true); + return; + } + } + } +} + bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) { // If we already selected that function, we do not need to run SDISel. if (mf.getProperties().hasProperty( @@ -589,6 +615,9 @@ // Determine if there is a call to setjmp in the machine function. MF->setExposesReturnsTwice(Fn.callsFunctionThatReturnsTwice()); + // Determine if floating point is used for msvc + computeUsesMSVCFloatingPoint(TM.getTargetTriple(), Fn, MF->getMMI()); + // Replace forward-declared registers with the registers containing // the desired value. MachineRegisterInfo &MRI = MF->getRegInfo(); Index: llvm/trunk/lib/Target/X86/X86AsmPrinter.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86AsmPrinter.cpp +++ llvm/trunk/lib/Target/X86/X86AsmPrinter.cpp @@ -682,26 +682,31 @@ // stripping. Since LLVM never generates code that does this, it is always // safe to set. OutStreamer->EmitAssemblerFlag(MCAF_SubsectionsViaSymbols); - return; - } - - if (TT.isKnownWindowsMSVCEnvironment() && MMI->usesVAFloatArgument()) { - StringRef SymbolName = - (TT.getArch() == Triple::x86_64) ? "_fltused" : "__fltused"; - MCSymbol *S = MMI->getContext().getOrCreateSymbol(SymbolName); - OutStreamer->EmitSymbolAttribute(S, MCSA_Global); - return; - } - - if (TT.isOSBinFormatCOFF()) { + } else if (TT.isOSBinFormatCOFF()) { + if (MMI->usesMSVCFloatingPoint()) { + // In Windows' libcmt.lib, there is a file which is linked in only if the + // symbol _fltused is referenced. Linking this in causes some + // side-effects: + // + // 1. For x86-32, it will set the x87 rounding mode to 53-bit instead of + // 64-bit mantissas at program start. + // + // 2. It links in support routines for floating-point in scanf and printf. + // + // MSVC emits an undefined reference to _fltused when there are any + // floating point operations in the program (including calls). A program + // that only has: `scanf("%f", &global_float);` may fail to trigger this, + // but oh well...that's a documented issue. + StringRef SymbolName = + (TT.getArch() == Triple::x86) ? "__fltused" : "_fltused"; + MCSymbol *S = MMI->getContext().getOrCreateSymbol(SymbolName); + OutStreamer->EmitSymbolAttribute(S, MCSA_Global); + return; + } emitStackMaps(SM); - return; - } - - if (TT.isOSBinFormatELF()) { + } else if (TT.isOSBinFormatELF()) { emitStackMaps(SM); FM.serializeToFaultMapSection(); - return; } } Index: llvm/trunk/test/CodeGen/X86/fltused.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/fltused.ll +++ llvm/trunk/test/CodeGen/X86/fltused.ll @@ -1,6 +1,5 @@ -; The purpose of this test to verify that the fltused symbol is emitted when -; any function is called with floating point arguments on Windows. And that it -; is not emitted otherwise. +; The purpose of this test to verify that the fltused symbol is +; emitted when a floating point call is made on Windows. ; RUN: llc < %s -mtriple i686-pc-win32 | FileCheck %s --check-prefix WIN32 ; RUN: llc < %s -mtriple x86_64-pc-win32 | FileCheck %s --check-prefix WIN64 Index: llvm/trunk/test/CodeGen/X86/fltused_function_pointer.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/fltused_function_pointer.ll +++ llvm/trunk/test/CodeGen/X86/fltused_function_pointer.ll @@ -1,6 +1,5 @@ -; The purpose of this test to verify that the fltused symbol is emitted when -; any function is called with floating point arguments on Windows. And that it -; is not emitted otherwise. +; The purpose of this test to verify that the fltused symbol is +; emitted when a floating point call is made on Windows. ; RUN: llc < %s -mtriple i686-pc-win32 | FileCheck %s --check-prefix WIN32 ; RUN: llc < %s -mtriple x86_64-pc-win32 | FileCheck %s --check-prefix WIN64 Index: llvm/trunk/test/CodeGen/X86/fltused_math.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/fltused_math.ll +++ llvm/trunk/test/CodeGen/X86/fltused_math.ll @@ -0,0 +1,18 @@ +; The purpose of this test to verify that the fltused symbol is +; emitted when floating point operations are used on Windows. + +; RUN: llc < %s -mtriple i686-pc-win32 | FileCheck %s --check-prefix WIN32 +; RUN: llc < %s -mtriple x86_64-pc-win32 | FileCheck %s --check-prefix WIN64 +; RUN: llc < %s -O0 -mtriple i686-pc-win32 | FileCheck %s --check-prefix WIN32 +; RUN: llc < %s -O0 -mtriple x86_64-pc-win32 | FileCheck %s --check-prefix WIN64 + +define i32 @foo(i32 %a) nounwind { +entry: + %da = sitofp i32 %a to double + %div = fdiv double %da, 3.100000e+00 + %res = fptosi double %div to i32 + ret i32 %res +} + +; WIN32: .globl __fltused +; WIN64: .globl _fltused