Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -3317,6 +3317,17 @@ // Verify call attributes. verifyFunctionAttrs(FTy, Attrs, &Call, IsIntrinsic, Call.isInlineAsm()); + // Verify strictfp attributes match. + Function *ContainingF = Call.getFunction(); + bool ContainingFHasStrictFP = ContainingF->hasFnAttribute(Attribute::StrictFP); + AttributeSet CallAttrs = Attrs.getFnAttrs(); + bool CallHasStrictFP = CallAttrs.hasAttribute(Attribute::StrictFP); + bool CalledFHasStrictFP = Call.hasFnAttr(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 +6023,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: \ Index: llvm/test/Verifier/fp-intrinsics.ll =================================================================== --- llvm/test/Verifier/fp-intrinsics.ll +++ llvm/test/Verifier/fp-intrinsics.ll @@ -51,4 +51,138 @@ 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 shall 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 _matched_ function and function call attributes, alias edition +; No diagnostic shall be printed. +@f10_alias = alias double (double), ptr @f10 +define double @f11(double %a) #0 { +entry: + %val = call double @f10_alias(double %a) #0 + ret double %val +} + +; Test for mismatched function and function call attributes, alias edition +; CHECK-NEXT: Functions and their contained calls and invokes must match in use of attribute strictfp! +; CHECK-NEXT: ptr @f12 +; CHECK-NEXT: %val = call double @f10_alias(double %a) +define double @f12(double %a) #0 { +entry: + %val = call double @f10_alias(double %a) + ret double %val +} + +; Test for mismatched function and function call attributes, alias edition +; CHECK-NEXT: Functions and their contained calls and invokes must match in use of attribute strictfp! +; CHECK-NEXT: ptr @f13 +; CHECK-NEXT: %val = call double @f10_alias(double %a) +define double @f13(double %a) { +entry: + %val = call double @f10_alias(double %a) #0 + ret double %val +} + +; Test for _matched_ function and function call attributes, indirect edition +; No diagnostic shall be printed. +define double @f14(double %a, double (double)* %func) #0 { +entry: + %val = call double %func(double %a) #0 + ret double %val +} + +; Test for mismatched function and function call attributes, indirect edition +; CHECK-NEXT: Functions and their contained calls and invokes must match in use of attribute strictfp! +; CHECK-NEXT: ptr @f15 +; CHECK-NEXT: %val = call double %func(double %a) +define double @f15(double %a, double (double)* %func) #0 { +entry: + %val = call double %func(double %a) + ret double %val +} + +; Test for mismatched function and function call attributes, indirect edition +; CHECK-NEXT: Functions and their contained calls and invokes must match in use of attribute strictfp! +; CHECK-NEXT: ptr @f16 +; CHECK-NEXT: %val = call double %func(double %a) +define double @f16(double %a, double (double)* %func) { +entry: + %val = call double %func(double %a) #0 + ret double %val +} + +; 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 }