Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -305,6 +305,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; @@ -2385,6 +2389,8 @@ // visitFunction - Verify that a function is ok. // void Verifier::visitFunction(const Function &F) { + HasConstrainedFP = false; + visitGlobalValue(F); // Check function arguments. @@ -2609,6 +2615,13 @@ Assert(false, "Invalid user of intrinsic instruction!", U); } + // Verify that the function has the correct attributes if a constrained + // floating-point value was seen. + if (HasConstrainedFP) + Assert (F.hasFnAttribute(Attribute::StrictFP), + "Constrained floating point requires function attribute strictfp!", + &F); + auto *N = F.getSubprogram(); HasDebugInfo = (N != nullptr); if (!HasDebugInfo) @@ -3155,6 +3168,15 @@ // Verify call attributes. verifyFunctionAttrs(FTy, Attrs, &Call, IsIntrinsic); + // Verify strictfp attributes match. + Function *ContainingF = Call.getFunction(); + AttributeSet CallAttrs = Attrs.getFnAttributes(); + Assert (ContainingF->hasFnAttribute(Attribute::StrictFP) == + CallAttrs.hasAttribute(Attribute::StrictFP), + "Functions and their contained calls and invokes 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. @@ -5336,6 +5358,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) \ 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,14 @@ ; 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 +; RUN: sed -e s/.T7I:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK7I %s +; RUN: sed -e s/.T8:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK8 %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 +82,52 @@ ;T5: ret double %fadd ;T5: } +; Test for mismatched function and function call attributes +; CHECK6: Functions and their contained calls and invokes 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 and invokes must match in use of attribute strictfp! +;T7: declare double @llvm.sqrt.f64(double) +;T7: define double @f7(double %a) #0 { +;T7: entry: +;T7: %sqrt = call double @llvm.sqrt.f64(double %a) +;T7: ret double %sqrt +;T7: } + +; Test for mismatched function and (invoke) function call attributes +; CHECK7I: Functions and their contained calls and invokes must match in use of attribute strictfp! +;T7I: declare double @doublefoo(double) +;T7I: define void @f7i(double %a) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) #0 { +;T7I: entry: +;T7I: invoke void @doublefoo(%a) +;T7I: to label %conta unwind label %contb +;T7I: +;T7I: conta: +;T7I: ret void +;T7I: +;T7I: contb: +;T7I: %0 = landingpad { i8*, i32 } +;T7I: filter [0 x i8*] zeroinitializer +;T7I: ret void +;T7I: } + +; Test for mismatched function and function call attributes +; CHECK8: Functions and their contained calls and invokes must match in use of attribute strictfp! +;T8: define double @f8(double %a) { +;T8: entry: +;T8: %fadd = call double @llvm.experimental.constrained.sqrt.f64( +;T8: double %a, +;T8: metadata !"round.dynamic", +;T8: metadata !"fpexcept.strict") #0 +;T8: ret double %fadd +;T8: } + attributes #0 = { strictfp }