forked from OSchip/llvm-project
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 llvm-svn: 255555
This commit is contained in:
parent
46642ffeeb
commit
fa54acedd1
|
@ -8314,7 +8314,7 @@ Syntax:
|
|||
|
||||
::
|
||||
|
||||
<result> = [tail | musttail | notail ] call [cconv] [ret attrs] <ty> [<fnty>*] <fnptrval>(<function args>) [fn attrs]
|
||||
<result> = [tail | musttail | notail ] call [fast-math flags] [cconv] [ret attrs] <ty> [<fnty>*] <fnptrval>(<function args>) [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 <fastmath>`, 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 <callingconv>` the call should use. If none is
|
||||
specified, the call defaults to using C calling conventions. The
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1532,19 +1532,26 @@ public:
|
|||
const Twine &Name = "") {
|
||||
return Insert(CallInst::Create(Callee, Args, OpBundles), Name);
|
||||
}
|
||||
|
||||
CallInst *CreateCall(Value *Callee, ArrayRef<Value *> Args,
|
||||
const Twine &Name) {
|
||||
return Insert(CallInst::Create(Callee, Args), Name);
|
||||
const Twine &Name, MDNode *FPMathTag = nullptr) {
|
||||
PointerType *PTy = cast<PointerType>(Callee->getType());
|
||||
FunctionType *FTy = cast<FunctionType>(PTy->getElementType());
|
||||
return CreateCall(FTy, Callee, Args, Name, FPMathTag);
|
||||
}
|
||||
|
||||
CallInst *CreateCall(llvm::FunctionType *FTy, Value *Callee,
|
||||
ArrayRef<Value *> Args, const Twine &Name = "") {
|
||||
return Insert(CallInst::Create(FTy, Callee, Args), Name);
|
||||
ArrayRef<Value *> Args, const Twine &Name = "",
|
||||
MDNode *FPMathTag = nullptr) {
|
||||
CallInst *CI = CallInst::Create(FTy, Callee, Args);
|
||||
if (isa<FPMathOperator>(CI))
|
||||
CI = cast<CallInst>(AddFPMathAttributes(CI, FPMathTag, FMF));
|
||||
return Insert(CI, Name);
|
||||
}
|
||||
|
||||
CallInst *CreateCall(Function *Callee, ArrayRef<Value *> 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,
|
||||
|
|
|
@ -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<OperandBundleDef, 2> 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;
|
||||
|
|
|
@ -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<FunctionType>(getTypeByID(Record[OpNum++]))))
|
||||
|
@ -5075,6 +5082,12 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
|
|||
TCK = CallInst::TCK_NoTail;
|
||||
cast<CallInst>(I)->setTailCallKind(TCK);
|
||||
cast<CallInst>(I)->setAttributes(PAL);
|
||||
if (FMF.any()) {
|
||||
if (!isa<FPMathOperator>(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]
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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: }
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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: }
|
||||
|
||||
|
|
|
@ -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: }
|
||||
|
||||
|
|
|
@ -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<Instruction>(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.
|
||||
|
|
Loading…
Reference in New Issue