Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -278,6 +278,10 @@ /// already. bool SawFrameEscape; + /// Whether or not we've seen constrained floating-point intrinsics + /// in a function. + bool HasConstrainedFP; + /// Whether the current function has a DISubprogram attached to it. bool HasDebugInfo = false; @@ -348,9 +352,11 @@ } Broken = false; + HasConstrainedFP = false; // FIXME: We strip const here because the inst visitor strips const. visit(const_cast(F)); verifySiblingFuncletUnwinds(); + verifyFunctionConstrainedFP(F); InstsInThisBlock.clear(); DebugFnArgs.clear(); LandingPadResultTy = nullptr; @@ -494,6 +500,7 @@ void visitCatchSwitchInst(CatchSwitchInst &CatchSwitch); void visitCleanupReturnInst(CleanupReturnInst &CRI); + void verifyFunctionConstrainedFP(const Function &F); void verifySwiftErrorCall(CallBase &Call, const Value *SwiftErrorVal); void verifySwiftErrorValue(const Value *SwiftErrorVal); void verifyMustTailCall(CallInst &CI); @@ -2371,6 +2378,19 @@ } } +// Verify that the function has the correct attributes if a constrained +// floating-point value was seen. +// +void Verifier::verifyFunctionConstrainedFP(const Function &F) { + if (HasConstrainedFP) { + AttributeList Attrs = F.getAttributes(); + AttributeSet FnAttrs = Attrs.getFnAttributes(); + Assert (FnAttrs.hasAttribute(Attribute::StrictFP), + "Constrained floating point requires function attribute strictfp!", + &F); + } +} + // verifyBasicBlock - Verify that a basic block is well formed... // void Verifier::visitBasicBlock(BasicBlock &BB) { @@ -2864,6 +2884,16 @@ // Verify call attributes. verifyFunctionAttrs(FTy, Attrs, &Call, IsIntrinsic); + // Verify strictfp attributes match. + Function *ContainingF = Call.getFunction(); + AttributeSet CFnAttrs = ContainingF->getAttributes().getFnAttributes(); + AttributeSet CallAttrs = Attrs.getFnAttributes(); + Assert (CFnAttrs.hasAttribute(Attribute::StrictFP) == + CallAttrs.hasAttribute(Attribute::StrictFP), + "Functions and their contained calls must match " + "in use of attribute strictfp!", + ContainingF, &Call); + // Conservatively check the inalloca argument. // We have a bug if we can find that there is an underlying alloca without // inalloca. @@ -4729,6 +4759,10 @@ void Verifier::visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI) { unsigned NumOperands; bool HasRoundingMD; + HasConstrainedFP = true; + AttributeSet CallAttrs = FPI.getAttributes().getFnAttributes(); + Assert (CallAttrs.hasAttribute(Attribute::StrictFP), + "Constrained FP intrinsics require strictfp attribute.", &FPI); switch (FPI.getIntrinsicID()) { #define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN) \ case Intrinsic::INTRINSIC: \ Index: llvm/test/Verifier/fp-intrinsics.ll =================================================================== --- llvm/test/Verifier/fp-intrinsics.ll +++ llvm/test/Verifier/fp-intrinsics.ll @@ -3,9 +3,12 @@ ; RUN: sed -e s/.T3:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK3 %s ; RUN: sed -e s/.T4:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK4 %s ; RUN: sed -e s/.T5:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK5 %s +; RUN: sed -e s/.T6:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK6 %s +; RUN: sed -e s/.T7:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK7 %s ; Common declarations used for all runs. declare double @llvm.experimental.constrained.fadd.f64(double, double, metadata, metadata) +declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) declare double @llvm.experimental.constrained.sqrt.f64(double, metadata, metadata) ; Test that the verifier accepts legal code, and that the correct attributes are @@ -77,4 +80,26 @@ ;T5: ret double %fadd ;T5: } +; Test for mismatched function and function call attributes +; CHECK6: Functions and their contained calls must match in use of attribute strictfp! +;T6: define double @f6(double %a) #0 { +;T6: entry: +;T6: %fadd = call double @llvm.experimental.constrained.sqrt.f64( +;T6: double %a, +;T6: metadata !"round.dynamic", +;T6: metadata !"fpexcept.strict") +;T6: ret double %fadd +;T6: } + +; Test for mismatched function and function call attributes +; CHECK7: Functions and their contained calls must match in use of attribute strictfp! +;T7: define double @f7(double %a) { +;T7: entry: +;T7: %fadd = call double @llvm.experimental.constrained.sqrt.f64( +;T7: double %a, +;T7: metadata !"round.dynamic", +;T7: metadata !"fpexcept.strict") #0 +;T7: ret double %fadd +;T7: } + attributes #0 = { strictfp }