diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -3317,6 +3317,21 @@ // Verify call attributes. verifyFunctionAttrs(FTy, Attrs, &Call, IsIntrinsic, Call.isInlineAsm()); + // Verify strictfp attributes match. + Function *ContainingF = Call.getFunction(); + Function *CalledF = Call.getCalledFunction(); + bool ContainingFHasStrictFP = ContainingF->hasFnAttribute(Attribute::StrictFP); + AttributeSet CallAttrs = Attrs.getFnAttrs(); + bool CallHasStrictFP = CallAttrs.hasAttribute(Attribute::StrictFP); + bool CalledFHasStrictFP = false; + if (CalledF) { + CalledFHasStrictFP = CalledF->hasFnAttribute(Attribute::StrictFP); + } + Check(ContainingFHasStrictFP == (CallHasStrictFP || CalledFHasStrictFP), + "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. @@ -6012,6 +6027,9 @@ void Verifier::visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI) { unsigned NumOperands; bool HasRoundingMD; + Check(FPI.getCaller()->hasFnAttribute(Attribute::StrictFP) == true, + "Constrained FP intrinsics require functions have strictfp attribute.", + FPI.getCaller()); switch (FPI.getIntrinsicID()) { #define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC) \ case Intrinsic::INTRINSIC: \ diff --git a/llvm/test/Verifier/fp-intrinsics.ll b/llvm/test/Verifier/fp-intrinsics.ll --- a/llvm/test/Verifier/fp-intrinsics.ll +++ b/llvm/test/Verifier/fp-intrinsics.ll @@ -51,4 +51,81 @@ ret double %fadd } +; Test for mismatched function and function call attributes +; CHECK-NEXT: Functions and their contained calls and invokes must match in use of attribute strictfp! +; CHECK-NEXT: ptr @f6 +; CHECK-NEXT: %fadd = call double @llvm.experimental.constrained.sqrt.f64(double %a, metadata !"round.dynamic", metadata !"fpexcept.strict") +define double @f6(double %a) #0 { +entry: + %fadd = call double @llvm.experimental.constrained.sqrt.f64( + double %a, + metadata !"round.dynamic", + metadata !"fpexcept.strict") + ret double %fadd +} + +; Test for mismatched function and function call attributes +; CHECK-NEXT: Functions and their contained calls and invokes must match in use of attribute strictfp! +; CHECK-NEXT: ptr @f7 +; CHECK-NEXT: %fadd = call double @llvm.experimental.constrained.sqrt.f64(double %a, metadata !"round.dynamic", metadata !"fpexcept.strict") #1 +define double @f7(double %a) { +entry: + %fadd = call double @llvm.experimental.constrained.sqrt.f64( + double %a, + metadata !"round.dynamic", + metadata !"fpexcept.strict") #0 + ret double %fadd +} + +; Test that strictfp attribute on function declaration counts. +; No diagnostic should be printed. +declare double @arbitrarystrictfp.f64(double) #0 +define double @f8(double %a) #0 { +entry: + %fadd = call double @arbitrarystrictfp.f64(double %a) + ret double %fadd +} + +; Test that strictfp attribute on function declaration counts. +; CHECK-NEXT: Functions and their contained calls and invokes must match in use of attribute strictfp! +; CHECK-NEXT: ptr @f9 +; CHECK-NEXT: %fadd = call double @arbitrarystrictfp.f64(double %a) +define double @f9(double %a) { +entry: + %fadd = call double @arbitrarystrictfp.f64(double %a) + ret double %fadd +} + +; Test for mismatched function and function call attributes +; CHECK-NEXT: Functions and their contained calls and invokes must match in use of attribute strictfp! +; CHECK-NEXT: ptr @f10 +; CHECK-NEXT: %sqrt = call double @llvm.sqrt.f64(double %a) +declare double @llvm.sqrt.f64(double) +define double @f10(double %a) #0 { +entry: + %sqrt = call double @llvm.sqrt.f64(double %a) + ret double %sqrt +} + +; Test for mismatched function and (invoke) function call attributes +; CHECK-NEXT: Functions and their contained calls and invokes must match in use of attribute strictfp! +; CHECK-NEXT: ptr @f100 +; CHECK-NEXT: %0 = invoke double @doublefoo(double %a) +; CHECK-NEXT: to label %conta unwind label %contb +declare double @doublefoo(double) +declare i32 @__gxx_personality_v0(...) +define void @f100(double %a) #0 personality ptr @__gxx_personality_v0 { +entry: + invoke double @doublefoo(double %a) + to label %conta unwind label %contb + +conta: + ret void + +contb: + %1 = landingpad { i8*, i32 } + filter [0 x i8*] zeroinitializer + ret void +} + attributes #0 = { strictfp }