Skip to content

Commit 2c36240

Browse files
committed
Fix emission of _fltused for MSVC.
It should be emitted when any floating-point operations (including calls) are present in the object, not just when calls to printf/scanf with floating point args are made. The difference caused by this is very subtle: in static (/MT) builds, on x86-32, in a program that uses floating point but doesn't print it, the default x87 rounding mode may not be set properly upon initialization. This commit also removes the walk of the types pointed to by pointer arguments in calls. (To assist in opaque pointer types migration -- eventually the pointee type won't be available.) That latter implies that it will no longer consider a call like `scanf("%f", &floatvar)` as sufficient to emit _fltused on its own. And without _fltused, `scanf("%f")` will abort with error R6002. This new behavior is unlikely to bite anyone in practice (you'd have to read a float, and do nothing with it!), and also, is consistent with MSVC. Differential Revision: https://reviews.llvm.org/D56548 llvm-svn: 352076
1 parent f4a1b54 commit 2c36240

File tree

9 files changed

+79
-67
lines changed

9 files changed

+79
-67
lines changed

llvm/include/llvm/CodeGen/MachineModuleInfo.h

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,9 @@ class MachineModuleInfo : public ImmutablePass {
113113
/// True if debugging information is available in this module.
114114
bool DbgInfoAvailable;
115115

116-
/// True if this module calls VarArg function with floating-point arguments.
117-
/// This is used to emit an undefined reference to _fltused on Windows
118-
/// targets.
119-
bool UsesVAFloatArgument;
116+
/// True if this module is being built for windows/msvc, and uses floating
117+
/// point. This is used to emit an undefined reference to _fltused.
118+
bool UsesMSVCFloatingPoint;
120119

121120
/// True if the module calls the __morestack function indirectly, as is
122121
/// required under the large code model on x86. This is used to emit
@@ -186,13 +185,9 @@ class MachineModuleInfo : public ImmutablePass {
186185
bool hasDebugInfo() const { return DbgInfoAvailable; }
187186
void setDebugInfoAvailability(bool avail) { DbgInfoAvailable = avail; }
188187

189-
bool usesVAFloatArgument() const {
190-
return UsesVAFloatArgument;
191-
}
188+
bool usesMSVCFloatingPoint() const { return UsesMSVCFloatingPoint; }
192189

193-
void setUsesVAFloatArgument(bool b) {
194-
UsesVAFloatArgument = b;
195-
}
190+
void setUsesMSVCFloatingPoint(bool b) { UsesMSVCFloatingPoint = b; }
196191

197192
bool usesMorestackAddr() const {
198193
return UsesMorestackAddr;
@@ -257,14 +252,6 @@ class MachineModuleInfo : public ImmutablePass {
257252
/// \}
258253
}; // End class MachineModuleInfo
259254

260-
//===- MMI building helpers -----------------------------------------------===//
261-
262-
/// Determine if any floating-point values are being passed to this variadic
263-
/// function, and set the MachineModuleInfo's usesVAFloatArgument flag if so.
264-
/// This flag is used to emit an undefined reference to _fltused on Windows,
265-
/// which will link in MSVCRT's floating-point support.
266-
void computeUsesVAFloatArgument(const CallInst &I, MachineModuleInfo &MMI);
267-
268255
} // end namespace llvm
269256

270257
#endif // LLVM_CODEGEN_MACHINEMODULEINFO_H

llvm/lib/CodeGen/MachineModuleInfo.cpp

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ MachineModuleInfo::~MachineModuleInfo() = default;
205205
bool MachineModuleInfo::doInitialization(Module &M) {
206206
ObjFileMMI = nullptr;
207207
CurCallSite = 0;
208-
UsesVAFloatArgument = UsesMorestackAddr = false;
208+
UsesMSVCFloatingPoint = UsesMorestackAddr = false;
209209
HasSplitStack = HasNosplitStack = false;
210210
AddrLabelSymbols = nullptr;
211211
TheModule = &M;
@@ -327,22 +327,3 @@ char FreeMachineFunction::ID;
327327
FunctionPass *llvm::createFreeMachineFunctionPass() {
328328
return new FreeMachineFunction();
329329
}
330-
331-
//===- MMI building helpers -----------------------------------------------===//
332-
333-
void llvm::computeUsesVAFloatArgument(const CallInst &I,
334-
MachineModuleInfo &MMI) {
335-
FunctionType *FT =
336-
cast<FunctionType>(I.getCalledValue()->getType()->getContainedType(0));
337-
if (FT->isVarArg() && !MMI.usesVAFloatArgument()) {
338-
for (unsigned i = 0, e = I.getNumArgOperands(); i != e; ++i) {
339-
Type *T = I.getArgOperand(i)->getType();
340-
for (auto i : post_order(T)) {
341-
if (i->isFloatingPointTy()) {
342-
MMI.setUsesVAFloatArgument(true);
343-
return;
344-
}
345-
}
346-
}
347-
}
348-
}

llvm/lib/CodeGen/SelectionDAG/FastISel.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,9 +1303,6 @@ bool FastISel::selectCall(const User *I) {
13031303
return true;
13041304
}
13051305

1306-
MachineModuleInfo &MMI = FuncInfo.MF->getMMI();
1307-
computeUsesVAFloatArgument(*Call, MMI);
1308-
13091306
// Handle intrinsic function calls.
13101307
if (const auto *II = dyn_cast<IntrinsicInst>(Call))
13111308
return selectIntrinsicCall(II);

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6987,9 +6987,6 @@ void SelectionDAGBuilder::visitCall(const CallInst &I) {
69876987
return;
69886988
}
69896989

6990-
MachineModuleInfo &MMI = DAG.getMachineFunction().getMMI();
6991-
computeUsesVAFloatArgument(I, MMI);
6992-
69936990
const char *RenameFn = nullptr;
69946991
if (Function *F = I.getCalledFunction()) {
69956992
if (F->isDeclaration()) {

llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "llvm/CodeGen/MachineInstr.h"
4242
#include "llvm/CodeGen/MachineInstrBuilder.h"
4343
#include "llvm/CodeGen/MachineMemOperand.h"
44+
#include "llvm/CodeGen/MachineModuleInfo.h"
4445
#include "llvm/CodeGen/MachineOperand.h"
4546
#include "llvm/CodeGen/MachinePassRegistry.h"
4647
#include "llvm/CodeGen/MachineRegisterInfo.h"
@@ -62,6 +63,7 @@
6263
#include "llvm/IR/Dominators.h"
6364
#include "llvm/IR/Function.h"
6465
#include "llvm/IR/InlineAsm.h"
66+
#include "llvm/IR/InstIterator.h"
6567
#include "llvm/IR/InstrTypes.h"
6668
#include "llvm/IR/Instruction.h"
6769
#include "llvm/IR/Instructions.h"
@@ -378,6 +380,30 @@ static void SplitCriticalSideEffectEdges(Function &Fn, DominatorTree *DT,
378380
}
379381
}
380382

383+
static void computeUsesMSVCFloatingPoint(const Triple &TT, const Function &F,
384+
MachineModuleInfo &MMI) {
385+
// Only needed for MSVC
386+
if (!TT.isKnownWindowsMSVCEnvironment())
387+
return;
388+
389+
// If it's already set, nothing to do.
390+
if (MMI.usesMSVCFloatingPoint())
391+
return;
392+
393+
for (const Instruction &I : instructions(F)) {
394+
if (I.getType()->isFPOrFPVectorTy()) {
395+
MMI.setUsesMSVCFloatingPoint(true);
396+
return;
397+
}
398+
for (const auto &Op : I.operands()) {
399+
if (Op->getType()->isFPOrFPVectorTy()) {
400+
MMI.setUsesMSVCFloatingPoint(true);
401+
return;
402+
}
403+
}
404+
}
405+
}
406+
381407
bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) {
382408
// If we already selected that function, we do not need to run SDISel.
383409
if (mf.getProperties().hasProperty(
@@ -589,6 +615,9 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) {
589615
// Determine if there is a call to setjmp in the machine function.
590616
MF->setExposesReturnsTwice(Fn.callsFunctionThatReturnsTwice());
591617

618+
// Determine if floating point is used for msvc
619+
computeUsesMSVCFloatingPoint(TM.getTargetTriple(), Fn, MF->getMMI());
620+
592621
// Replace forward-declared registers with the registers containing
593622
// the desired value.
594623
MachineRegisterInfo &MRI = MF->getRegInfo();

llvm/lib/Target/X86/X86AsmPrinter.cpp

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -682,26 +682,31 @@ void X86AsmPrinter::EmitEndOfAsmFile(Module &M) {
682682
// stripping. Since LLVM never generates code that does this, it is always
683683
// safe to set.
684684
OutStreamer->EmitAssemblerFlag(MCAF_SubsectionsViaSymbols);
685-
return;
686-
}
687-
688-
if (TT.isKnownWindowsMSVCEnvironment() && MMI->usesVAFloatArgument()) {
689-
StringRef SymbolName =
690-
(TT.getArch() == Triple::x86_64) ? "_fltused" : "__fltused";
691-
MCSymbol *S = MMI->getContext().getOrCreateSymbol(SymbolName);
692-
OutStreamer->EmitSymbolAttribute(S, MCSA_Global);
693-
return;
694-
}
695-
696-
if (TT.isOSBinFormatCOFF()) {
685+
} else if (TT.isOSBinFormatCOFF()) {
686+
if (MMI->usesMSVCFloatingPoint()) {
687+
// In Windows' libcmt.lib, there is a file which is linked in only if the
688+
// symbol _fltused is referenced. Linking this in causes some
689+
// side-effects:
690+
//
691+
// 1. For x86-32, it will set the x87 rounding mode to 53-bit instead of
692+
// 64-bit mantissas at program start.
693+
//
694+
// 2. It links in support routines for floating-point in scanf and printf.
695+
//
696+
// MSVC emits an undefined reference to _fltused when there are any
697+
// floating point operations in the program (including calls). A program
698+
// that only has: `scanf("%f", &global_float);` may fail to trigger this,
699+
// but oh well...that's a documented issue.
700+
StringRef SymbolName =
701+
(TT.getArch() == Triple::x86) ? "__fltused" : "_fltused";
702+
MCSymbol *S = MMI->getContext().getOrCreateSymbol(SymbolName);
703+
OutStreamer->EmitSymbolAttribute(S, MCSA_Global);
704+
return;
705+
}
697706
emitStackMaps(SM);
698-
return;
699-
}
700-
701-
if (TT.isOSBinFormatELF()) {
707+
} else if (TT.isOSBinFormatELF()) {
702708
emitStackMaps(SM);
703709
FM.serializeToFaultMapSection();
704-
return;
705710
}
706711
}
707712

llvm/test/CodeGen/X86/fltused.ll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
; The purpose of this test to verify that the fltused symbol is emitted when
2-
; any function is called with floating point arguments on Windows. And that it
3-
; is not emitted otherwise.
1+
; The purpose of this test to verify that the fltused symbol is
2+
; emitted when a floating point call is made on Windows.
43

54
; RUN: llc < %s -mtriple i686-pc-win32 | FileCheck %s --check-prefix WIN32
65
; RUN: llc < %s -mtriple x86_64-pc-win32 | FileCheck %s --check-prefix WIN64

llvm/test/CodeGen/X86/fltused_function_pointer.ll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
; The purpose of this test to verify that the fltused symbol is emitted when
2-
; any function is called with floating point arguments on Windows. And that it
3-
; is not emitted otherwise.
1+
; The purpose of this test to verify that the fltused symbol is
2+
; emitted when a floating point call is made on Windows.
43

54
; RUN: llc < %s -mtriple i686-pc-win32 | FileCheck %s --check-prefix WIN32
65
; RUN: llc < %s -mtriple x86_64-pc-win32 | FileCheck %s --check-prefix WIN64

llvm/test/CodeGen/X86/fltused_math.ll

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
; The purpose of this test to verify that the fltused symbol is
2+
; emitted when floating point operations are used on Windows.
3+
4+
; RUN: llc < %s -mtriple i686-pc-win32 | FileCheck %s --check-prefix WIN32
5+
; RUN: llc < %s -mtriple x86_64-pc-win32 | FileCheck %s --check-prefix WIN64
6+
; RUN: llc < %s -O0 -mtriple i686-pc-win32 | FileCheck %s --check-prefix WIN32
7+
; RUN: llc < %s -O0 -mtriple x86_64-pc-win32 | FileCheck %s --check-prefix WIN64
8+
9+
define i32 @foo(i32 %a) nounwind {
10+
entry:
11+
%da = sitofp i32 %a to double
12+
%div = fdiv double %da, 3.100000e+00
13+
%res = fptosi double %div to i32
14+
ret i32 %res
15+
}
16+
17+
; WIN32: .globl __fltused
18+
; WIN64: .globl _fltused

0 commit comments

Comments
 (0)