From a3a48d96c997f098f504a250ccd38dcb773c233c Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Mon, 14 Dec 2015 21:59:03 +0000 Subject: [PATCH] add fast-math-flags to 'call' instructions (PR21290) This patch adds optional fast-math-flags (the same that apply to fmul/fadd/fsub/fdiv/frem/fcmp) to call instructions in IR. Follow-up patches would use these flags in LibCallSimplifier, add support to clang, and extend FMF to the DAG for calls. Motivating example: %y = fmul fast float %x, %x %z = tail call float @sqrtf(float %y) We'd like to be able to optimize sqrt(x*x) into fabs(x). We do this today using a function-wide attribute for unsafe-math, but we really want to trigger on the instructions themselves: %z = tail call fast float @sqrtf(float %y) because in an LTO build it's possible that calls with fast semantics have been inlined into a function with non-fast semantics. The code changes and tests are based on the recent commits that added "notail": http://reviews.llvm.org/rL252368 and added FMF to fcmp: http://reviews.llvm.org/rL241901 Differential Revision: http://reviews.llvm.org/D14707 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@255555 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LangRef.rst | 7 +++- include/llvm/Bitcode/LLVMBitCodes.h | 3 +- include/llvm/IR/IRBuilder.h | 19 +++++++---- lib/AsmParser/LLParser.cpp | 34 ++++++++++++------- lib/Bitcode/Reader/BitcodeReader.cpp | 15 +++++++- lib/Bitcode/Writer/BitcodeWriter.cpp | 8 ++++- test/Bitcode/compatibility.ll | 22 ++++++++++++ test/Transforms/InstCombine/fast-math.ll | 34 +++++++++---------- .../InstCombine/inline-intrinsic-assert.ll | 2 +- test/Transforms/InstCombine/log-pow.ll | 2 +- .../Transforms/InstCombine/no_cgscc_assert.ll | 2 +- test/Transforms/InstCombine/pow-exp.ll | 2 +- test/Transforms/InstCombine/pow-exp2.ll | 2 +- unittests/IR/IRBuilderTest.cpp | 22 +++++++++++- 14 files changed, 129 insertions(+), 45 deletions(-) diff --git a/docs/LangRef.rst b/docs/LangRef.rst index a0c23f9a213..79856a304c1 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -8314,7 +8314,7 @@ Syntax: :: - = [tail | musttail | notail ] call [cconv] [ret attrs] [*] () [fn attrs] + = [tail | musttail | notail ] call [fast-math flags] [cconv] [ret attrs] [*] () [fn attrs] [ operand bundles ] Overview: @@ -8371,6 +8371,11 @@ This instruction requires several arguments: ``tail`` or ``musttail`` markers to the call. It is used to prevent tail call optimization from being performed on the call. +#. The optional ``fast-math flags`` marker indicates that the call has one or more + :ref:`fast-math flags `, which are optimization hints to enable + otherwise unsafe floating-point optimizations. Fast-math flags are only valid + for calls that return a floating-point scalar or vector type. + #. The optional "cconv" marker indicates which :ref:`calling convention ` the call should use. If none is specified, the call defaults to using C calling conventions. The diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index b967f58d847..6780c8e6a97 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -348,7 +348,8 @@ enum { BITCODE_CURRENT_EPOCH = 0 }; CALL_CCONV = 1, CALL_MUSTTAIL = 14, CALL_EXPLICIT_TYPE = 15, - CALL_NOTAIL = 16 + CALL_NOTAIL = 16, + CALL_FMF = 17 // Call has optional fast-math-flags. }; // The function body block (FUNCTION_BLOCK_ID) describes function bodies. It diff --git a/include/llvm/IR/IRBuilder.h b/include/llvm/IR/IRBuilder.h index 1fa88013ef2..7fe04f2a091 100644 --- a/include/llvm/IR/IRBuilder.h +++ b/include/llvm/IR/IRBuilder.h @@ -1532,19 +1532,26 @@ public: const Twine &Name = "") { return Insert(CallInst::Create(Callee, Args, OpBundles), Name); } + CallInst *CreateCall(Value *Callee, ArrayRef Args, - const Twine &Name) { - return Insert(CallInst::Create(Callee, Args), Name); + const Twine &Name, MDNode *FPMathTag = nullptr) { + PointerType *PTy = cast(Callee->getType()); + FunctionType *FTy = cast(PTy->getElementType()); + return CreateCall(FTy, Callee, Args, Name, FPMathTag); } CallInst *CreateCall(llvm::FunctionType *FTy, Value *Callee, - ArrayRef Args, const Twine &Name = "") { - return Insert(CallInst::Create(FTy, Callee, Args), Name); + ArrayRef Args, const Twine &Name = "", + MDNode *FPMathTag = nullptr) { + CallInst *CI = CallInst::Create(FTy, Callee, Args); + if (isa(CI)) + CI = cast(AddFPMathAttributes(CI, FPMathTag, FMF)); + return Insert(CI, Name); } CallInst *CreateCall(Function *Callee, ArrayRef Args, - const Twine &Name = "") { - return CreateCall(Callee->getFunctionType(), Callee, Args, Name); + const Twine &Name = "", MDNode *FPMathTag = nullptr) { + return CreateCall(Callee->getFunctionType(), Callee, Args, Name, FPMathTag); } Value *CreateSelect(Value *C, Value *True, Value *False, diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 3d43f81f49a..0b2880949f6 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -5603,14 +5603,14 @@ bool LLParser::ParseLandingPad(Instruction *&Inst, PerFunctionState &PFS) { } /// ParseCall -/// ::= 'call' OptionalCallingConv OptionalAttrs Type Value -/// ParameterList OptionalAttrs -/// ::= 'tail' 'call' OptionalCallingConv OptionalAttrs Type Value -/// ParameterList OptionalAttrs -/// ::= 'musttail' 'call' OptionalCallingConv OptionalAttrs Type Value -/// ParameterList OptionalAttrs -/// ::= 'notail' 'call' OptionalCallingConv OptionalAttrs Type Value -/// ParameterList OptionalAttrs +/// ::= 'call' OptionalFastMathFlags OptionalCallingConv +/// OptionalAttrs Type Value ParameterList OptionalAttrs +/// ::= 'tail' 'call' OptionalFastMathFlags OptionalCallingConv +/// OptionalAttrs Type Value ParameterList OptionalAttrs +/// ::= 'musttail' 'call' OptionalFastMathFlags OptionalCallingConv +/// OptionalAttrs Type Value ParameterList OptionalAttrs +/// ::= 'notail' 'call' OptionalFastMathFlags OptionalCallingConv +/// OptionalAttrs Type Value ParameterList OptionalAttrs bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS, CallInst::TailCallKind TCK) { AttrBuilder RetAttrs, FnAttrs; @@ -5624,10 +5624,14 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS, SmallVector BundleList; LocTy CallLoc = Lex.getLoc(); - if ((TCK != CallInst::TCK_None && - ParseToken(lltok::kw_call, - "expected 'tail call', 'musttail call', or 'notail call'")) || - ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) || + if (TCK != CallInst::TCK_None && + ParseToken(lltok::kw_call, + "expected 'tail call', 'musttail call', or 'notail call'")) + return true; + + FastMathFlags FMF = EatFastMathFlagsIfPresent(); + + if (ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) || ParseType(RetType, RetTypeLoc, true /*void allowed*/) || ParseValID(CalleeID) || ParseParameterList(ArgList, PFS, TCK == CallInst::TCK_MustTail, @@ -5636,6 +5640,10 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS, ParseOptionalOperandBundles(BundleList, PFS)) return true; + if (FMF.any() && !RetType->isFPOrFPVectorTy()) + return Error(CallLoc, "fast-math-flags specified for call without " + "floating-point scalar or vector return type"); + // If RetType is a non-function pointer type, then this is the short syntax // for the call, which means that RetType is just the return type. Infer the // rest of the function argument types from the arguments that are present. @@ -5708,6 +5716,8 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS, CallInst *CI = CallInst::Create(Ty, Callee, Args, BundleList); CI->setTailCallKind(TCK); CI->setCallingConv(CC); + if (FMF.any()) + CI->setFastMathFlags(FMF); CI->setAttributes(PAL); ForwardRefAttrGroups[CI] = FwdRefAttrGrps; Inst = CI; diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 210ffd8d912..d59f12898e9 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -5006,7 +5006,7 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { break; } case bitc::FUNC_CODE_INST_CALL: { - // CALL: [paramattrs, cc, fnty, fnid, arg0, arg1...] + // CALL: [paramattrs, cc, fmf, fnty, fnid, arg0, arg1...] if (Record.size() < 3) return error("Invalid record"); @@ -5014,6 +5014,13 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { AttributeSet PAL = getAttributes(Record[OpNum++]); unsigned CCInfo = Record[OpNum++]; + FastMathFlags FMF; + if ((CCInfo >> bitc::CALL_FMF) & 1) { + FMF = getDecodedFastMathFlags(Record[OpNum++]); + if (!FMF.any()) + return error("Fast math flags indicator set for call with no FMF"); + } + FunctionType *FTy = nullptr; if (CCInfo >> bitc::CALL_EXPLICIT_TYPE & 1 && !(FTy = dyn_cast(getTypeByID(Record[OpNum++])))) @@ -5075,6 +5082,12 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { TCK = CallInst::TCK_NoTail; cast(I)->setTailCallKind(TCK); cast(I)->setAttributes(PAL); + if (FMF.any()) { + if (!isa(I)) + return error("Fast-math-flags specified for call without " + "floating-point scalar or vector return type"); + I->setFastMathFlags(FMF); + } break; } case bitc::FUNC_CODE_INST_VAARG: { // VAARG: [valistty, valist, instty] diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index dd4a16d985f..e34ce5ac430 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2153,11 +2153,17 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, Code = bitc::FUNC_CODE_INST_CALL; Vals.push_back(VE.getAttributeID(CI.getAttributes())); + + unsigned Flags = GetOptimizationFlags(&I); Vals.push_back(CI.getCallingConv() << bitc::CALL_CCONV | unsigned(CI.isTailCall()) << bitc::CALL_TAIL | unsigned(CI.isMustTailCall()) << bitc::CALL_MUSTTAIL | 1 << bitc::CALL_EXPLICIT_TYPE | - unsigned(CI.isNoTailCall()) << bitc::CALL_NOTAIL); + unsigned(CI.isNoTailCall()) << bitc::CALL_NOTAIL | + unsigned(Flags != 0) << bitc::CALL_FMF); + if (Flags != 0) + Vals.push_back(Flags); + Vals.push_back(VE.getTypeID(FTy)); PushValueAndType(CI.getCalledValue(), InstID, Vals, VE); // Callee diff --git a/test/Bitcode/compatibility.ll b/test/Bitcode/compatibility.ll index de0fc137e53..465facc2a88 100644 --- a/test/Bitcode/compatibility.ll +++ b/test/Bitcode/compatibility.ll @@ -664,6 +664,28 @@ define void @fastmathflags(float %op1, float %op2) { ret void } +; Check various fast math flags and floating-point types on calls. + +declare float @fmf1() +declare double @fmf2() +declare <4 x double> @fmf3() + +; CHECK-LABEL: fastMathFlagsForCalls( +define void @fastMathFlagsForCalls(float %f, double %d1, <4 x double> %d2) { + %call.fast = call fast float @fmf1() + ; CHECK: %call.fast = call fast float @fmf1() + + ; Throw in some other attributes to make sure those stay in the right places. + + %call.nsz.arcp = notail call nsz arcp double @fmf2() + ; CHECK: %call.nsz.arcp = notail call nsz arcp double @fmf2() + + %call.nnan.ninf = tail call nnan ninf fastcc <4 x double> @fmf3() + ; CHECK: %call.nnan.ninf = tail call nnan ninf fastcc <4 x double> @fmf3() + + ret void +} + ;; Type System %opaquety = type opaque define void @typesystem() { diff --git a/test/Transforms/InstCombine/fast-math.ll b/test/Transforms/InstCombine/fast-math.ll index 06852497564..fd563481b3e 100644 --- a/test/Transforms/InstCombine/fast-math.ll +++ b/test/Transforms/InstCombine/fast-math.ll @@ -570,7 +570,7 @@ define double @sqrt_intrinsic_arg_squared(double %x) #0 { ret double %sqrt ; CHECK-LABEL: sqrt_intrinsic_arg_squared( -; CHECK-NEXT: %fabs = call double @llvm.fabs.f64(double %x) +; CHECK-NEXT: %fabs = call fast double @llvm.fabs.f64(double %x) ; CHECK-NEXT: ret double %fabs } @@ -584,8 +584,8 @@ define double @sqrt_intrinsic_three_args1(double %x, double %y) #0 { ret double %sqrt ; CHECK-LABEL: sqrt_intrinsic_three_args1( -; CHECK-NEXT: %fabs = call double @llvm.fabs.f64(double %x) -; CHECK-NEXT: %sqrt1 = call double @llvm.sqrt.f64(double %y) +; CHECK-NEXT: %fabs = call fast double @llvm.fabs.f64(double %x) +; CHECK-NEXT: %sqrt1 = call fast double @llvm.sqrt.f64(double %y) ; CHECK-NEXT: %1 = fmul fast double %fabs, %sqrt1 ; CHECK-NEXT: ret double %1 } @@ -597,8 +597,8 @@ define double @sqrt_intrinsic_three_args2(double %x, double %y) #0 { ret double %sqrt ; CHECK-LABEL: sqrt_intrinsic_three_args2( -; CHECK-NEXT: %fabs = call double @llvm.fabs.f64(double %x) -; CHECK-NEXT: %sqrt1 = call double @llvm.sqrt.f64(double %y) +; CHECK-NEXT: %fabs = call fast double @llvm.fabs.f64(double %x) +; CHECK-NEXT: %sqrt1 = call fast double @llvm.sqrt.f64(double %y) ; CHECK-NEXT: %1 = fmul fast double %fabs, %sqrt1 ; CHECK-NEXT: ret double %1 } @@ -610,8 +610,8 @@ define double @sqrt_intrinsic_three_args3(double %x, double %y) #0 { ret double %sqrt ; CHECK-LABEL: sqrt_intrinsic_three_args3( -; CHECK-NEXT: %fabs = call double @llvm.fabs.f64(double %x) -; CHECK-NEXT: %sqrt1 = call double @llvm.sqrt.f64(double %y) +; CHECK-NEXT: %fabs = call fast double @llvm.fabs.f64(double %x) +; CHECK-NEXT: %sqrt1 = call fast double @llvm.sqrt.f64(double %y) ; CHECK-NEXT: %1 = fmul fast double %fabs, %sqrt1 ; CHECK-NEXT: ret double %1 } @@ -623,8 +623,8 @@ define double @sqrt_intrinsic_three_args4(double %x, double %y) #0 { ret double %sqrt ; CHECK-LABEL: sqrt_intrinsic_three_args4( -; CHECK-NEXT: %fabs = call double @llvm.fabs.f64(double %x) -; CHECK-NEXT: %sqrt1 = call double @llvm.sqrt.f64(double %y) +; CHECK-NEXT: %fabs = call fast double @llvm.fabs.f64(double %x) +; CHECK-NEXT: %sqrt1 = call fast double @llvm.sqrt.f64(double %y) ; CHECK-NEXT: %1 = fmul fast double %fabs, %sqrt1 ; CHECK-NEXT: ret double %1 } @@ -636,8 +636,8 @@ define double @sqrt_intrinsic_three_args5(double %x, double %y) #0 { ret double %sqrt ; CHECK-LABEL: sqrt_intrinsic_three_args5( -; CHECK-NEXT: %fabs = call double @llvm.fabs.f64(double %x) -; CHECK-NEXT: %sqrt1 = call double @llvm.sqrt.f64(double %y) +; CHECK-NEXT: %fabs = call fast double @llvm.fabs.f64(double %x) +; CHECK-NEXT: %sqrt1 = call fast double @llvm.sqrt.f64(double %y) ; CHECK-NEXT: %1 = fmul fast double %fabs, %sqrt1 ; CHECK-NEXT: ret double %1 } @@ -649,8 +649,8 @@ define double @sqrt_intrinsic_three_args6(double %x, double %y) #0 { ret double %sqrt ; CHECK-LABEL: sqrt_intrinsic_three_args6( -; CHECK-NEXT: %fabs = call double @llvm.fabs.f64(double %x) -; CHECK-NEXT: %sqrt1 = call double @llvm.sqrt.f64(double %y) +; CHECK-NEXT: %fabs = call fast double @llvm.fabs.f64(double %x) +; CHECK-NEXT: %sqrt1 = call fast double @llvm.sqrt.f64(double %y) ; CHECK-NEXT: %1 = fmul fast double %fabs, %sqrt1 ; CHECK-NEXT: ret double %1 } @@ -675,7 +675,7 @@ define double @sqrt_intrinsic_arg_5th(double %x) #0 { ; CHECK-LABEL: sqrt_intrinsic_arg_5th( ; CHECK-NEXT: %mul = fmul fast double %x, %x -; CHECK-NEXT: %sqrt1 = call double @llvm.sqrt.f64(double %x) +; CHECK-NEXT: %sqrt1 = call fast double @llvm.sqrt.f64(double %x) ; CHECK-NEXT: %1 = fmul fast double %mul, %sqrt1 ; CHECK-NEXT: ret double %1 } @@ -692,7 +692,7 @@ define float @sqrt_call_squared_f32(float %x) #0 { ret float %sqrt ; CHECK-LABEL: sqrt_call_squared_f32( -; CHECK-NEXT: %fabs = call float @llvm.fabs.f32(float %x) +; CHECK-NEXT: %fabs = call fast float @llvm.fabs.f32(float %x) ; CHECK-NEXT: ret float %fabs } @@ -702,7 +702,7 @@ define double @sqrt_call_squared_f64(double %x) #0 { ret double %sqrt ; CHECK-LABEL: sqrt_call_squared_f64( -; CHECK-NEXT: %fabs = call double @llvm.fabs.f64(double %x) +; CHECK-NEXT: %fabs = call fast double @llvm.fabs.f64(double %x) ; CHECK-NEXT: ret double %fabs } @@ -712,7 +712,7 @@ define fp128 @sqrt_call_squared_f128(fp128 %x) #0 { ret fp128 %sqrt ; CHECK-LABEL: sqrt_call_squared_f128( -; CHECK-NEXT: %fabs = call fp128 @llvm.fabs.f128(fp128 %x) +; CHECK-NEXT: %fabs = call fast fp128 @llvm.fabs.f128(fp128 %x) ; CHECK-NEXT: ret fp128 %fabs } diff --git a/test/Transforms/InstCombine/inline-intrinsic-assert.ll b/test/Transforms/InstCombine/inline-intrinsic-assert.ll index af34277563e..c6446d43cff 100644 --- a/test/Transforms/InstCombine/inline-intrinsic-assert.ll +++ b/test/Transforms/InstCombine/inline-intrinsic-assert.ll @@ -9,7 +9,7 @@ define float @foo(float %f1) #0 { ret float %call ; CHECK-LABEL: @foo( -; CHECK-NEXT: call float @llvm.fabs.f32 +; CHECK-NEXT: call fast float @llvm.fabs.f32 ; CHECK-NEXT: ret float } diff --git a/test/Transforms/InstCombine/log-pow.ll b/test/Transforms/InstCombine/log-pow.ll index 1acd0354431..c5ca1688d34 100644 --- a/test/Transforms/InstCombine/log-pow.ll +++ b/test/Transforms/InstCombine/log-pow.ll @@ -8,7 +8,7 @@ entry: } ; CHECK-LABEL: define double @mylog( -; CHECK: %log = call double @log(double %x) #0 +; CHECK: %log = call fast double @log(double %x) #0 ; CHECK: %mul = fmul fast double %log, %y ; CHECK: ret double %mul ; CHECK: } diff --git a/test/Transforms/InstCombine/no_cgscc_assert.ll b/test/Transforms/InstCombine/no_cgscc_assert.ll index cec5297695b..3df04d2c890 100644 --- a/test/Transforms/InstCombine/no_cgscc_assert.ll +++ b/test/Transforms/InstCombine/no_cgscc_assert.ll @@ -10,7 +10,7 @@ define float @bar(float %f) #0 { ret float %call1 ; CHECK-LABEL: @bar( -; CHECK-NEXT: call float @llvm.fabs.f32 +; CHECK-NEXT: call fast float @llvm.fabs.f32 ; CHECK-NEXT: ret float } diff --git a/test/Transforms/InstCombine/pow-exp.ll b/test/Transforms/InstCombine/pow-exp.ll index 7ac6fe4f8fd..acc512734ec 100644 --- a/test/Transforms/InstCombine/pow-exp.ll +++ b/test/Transforms/InstCombine/pow-exp.ll @@ -9,7 +9,7 @@ entry: ; CHECK-LABEL: define double @mypow( ; CHECK: %mul = fmul fast double %x, %y -; CHECK: %exp = call double @exp(double %mul) #0 +; CHECK: %exp = call fast double @exp(double %mul) #0 ; CHECK: ret double %exp ; CHECK: } diff --git a/test/Transforms/InstCombine/pow-exp2.ll b/test/Transforms/InstCombine/pow-exp2.ll index ad7931c07a6..c42cab391e6 100644 --- a/test/Transforms/InstCombine/pow-exp2.ll +++ b/test/Transforms/InstCombine/pow-exp2.ll @@ -9,7 +9,7 @@ entry: ; CHECK-LABEL: define double @mypow( ; CHECK: %mul = fmul fast double %x, %y -; CHECK: %exp2 = call double @exp2(double %mul) #0 +; CHECK: %exp2 = call fast double @exp2(double %mul) #0 ; CHECK: ret double %exp2 ; CHECK: } diff --git a/unittests/IR/IRBuilderTest.cpp b/unittests/IR/IRBuilderTest.cpp index 0c602ed2b78..e0da018d7bf 100644 --- a/unittests/IR/IRBuilderTest.cpp +++ b/unittests/IR/IRBuilderTest.cpp @@ -131,7 +131,7 @@ TEST_F(IRBuilderTest, GetIntTy) { TEST_F(IRBuilderTest, FastMathFlags) { IRBuilder<> Builder(BB); Value *F, *FC; - Instruction *FDiv, *FAdd, *FCmp; + Instruction *FDiv, *FAdd, *FCmp, *FCall; F = Builder.CreateLoad(GV); F = Builder.CreateFAdd(F, F); @@ -206,6 +206,26 @@ TEST_F(IRBuilderTest, FastMathFlags) { FCmp = cast(FC); EXPECT_TRUE(FCmp->hasAllowReciprocal()); + Builder.clearFastMathFlags(); + + // Test a call with FMF. + auto CalleeTy = FunctionType::get(Type::getFloatTy(Ctx), + /*isVarArg=*/false); + auto Callee = + Function::Create(CalleeTy, Function::ExternalLinkage, "", M.get()); + + FCall = Builder.CreateCall(Callee, None); + EXPECT_FALSE(FCall->hasNoNaNs()); + + FMF.clear(); + FMF.setNoNaNs(); + Builder.SetFastMathFlags(FMF); + + FCall = Builder.CreateCall(Callee, None); + EXPECT_TRUE(Builder.getFastMathFlags().any()); + EXPECT_TRUE(Builder.getFastMathFlags().NoNaNs); + EXPECT_TRUE(FCall->hasNoNaNs()); + Builder.clearFastMathFlags(); // To test a copy, make sure that a '0' and a '1' change state. -- 2.34.1