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 @@ -309,6 +309,10 @@ /// in a function. bool HasConstrainedFP; + /// Whether or not we've seen normal floating-point instructions in + /// a function. + bool HasUnconstrainedFP; + /// Whether the current function has a DISubprogram attached to it. bool HasDebugInfo = false; @@ -2390,6 +2394,7 @@ // void Verifier::visitFunction(const Function &F) { HasConstrainedFP = false; + HasUnconstrainedFP = false; visitGlobalValue(F); @@ -2622,6 +2627,10 @@ "Constrained floating point requires function attribute strictfp!", &F); + if (HasUnconstrainedFP && HasConstrainedFP) // XXX different why? + CheckFailed( + "Constrained and normal floating-point cannot be mixed in a function!"); + auto *N = F.getSubprogram(); HasDebugInfo = (N != nullptr); if (!HasDebugInfo) @@ -2900,6 +2909,8 @@ "fptrunc source and destination must both be a vector or neither", &I); Assert(SrcBitSize > DestBitSize, "DestTy too big for FPTrunc", &I); + HasUnconstrainedFP = true; + visitInstruction(I); } @@ -2918,6 +2929,8 @@ "fpext source and destination must both be a vector or neither", &I); Assert(SrcBitSize < DestBitSize, "DestTy too small for FPExt", &I); + HasUnconstrainedFP = true; + visitInstruction(I); } @@ -2941,6 +2954,8 @@ cast(DestTy)->getElementCount(), "UIToFP source and dest vector length mismatch", &I); + HasUnconstrainedFP = true; + visitInstruction(I); } @@ -2964,6 +2979,8 @@ cast(DestTy)->getElementCount(), "SIToFP source and dest vector length mismatch", &I); + HasUnconstrainedFP = true; + visitInstruction(I); } @@ -2987,6 +3004,8 @@ cast(DestTy)->getElementCount(), "FPToUI source and dest vector length mismatch", &I); + HasUnconstrainedFP = true; + visitInstruction(I); } @@ -3010,6 +3029,8 @@ cast(DestTy)->getElementCount(), "FPToSI source and dest vector length mismatch", &I); + HasUnconstrainedFP = true; + visitInstruction(I); } @@ -3503,6 +3524,7 @@ // Check that floating-point arithmetic operators are only used with // floating-point operands. case Instruction::FNeg: + // No constrained version, so no need to set any flags here. Assert(U.getType()->isFPOrFPVectorTy(), "FNeg operator only works with float types!", &U); break; @@ -3552,6 +3574,7 @@ "Floating-point arithmetic operators must have same type " "for operands and result!", &B); + HasUnconstrainedFP = true; break; // Check that logical operators are only used with integral operands. case Instruction::And: @@ -3607,6 +3630,8 @@ Assert(FC.isFPPredicate(), "Invalid predicate in FCmp instruction!", &FC); + HasUnconstrainedFP = true; // XXX what about select? + visitInstruction(FC); } 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 @@ -7,11 +7,17 @@ ; 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 +; RUN: sed -e s/.T9:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK9 %s +; RUN: sed -e s/.T10:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK10 %s +; RUN: sed -e s/.T11:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK11 %s +; RUN: sed -e s/.T12:// %s | opt -verify -disable-output 2>&1 ; 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) +declare float @llvm.experimental.constrained.fptrunc.f32.f64(double, metadata, metadata) +declare double @llvm.experimental.constrained.fpext.f64.f32(float, metadata) ; Test that the verifier accepts legal code, and that the correct attributes are ; attached to the FP intrinsic. @@ -98,8 +104,11 @@ ;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: %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: } ; Test for mismatched function and (invoke) function call attributes @@ -109,10 +118,10 @@ ;T7I: entry: ;T7I: invoke void @doublefoo(%a) ;T7I: to label %conta unwind label %contb -;T7I: +;T7I: ;T7I: conta: ;T7I: ret void -;T7I: +;T7I: ;T7I: contb: ;T7I: %0 = landingpad { i8*, i32 } ;T7I: filter [0 x i8*] zeroinitializer @@ -123,11 +132,74 @@ ; 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: %fadd = call double @llvm.experimental.constrained.fadd.f64( +;T8: double %a, double %b, +;T8: metadata !"round.dynamic", +;T8: metadata !"fpexcept.strict") #0 +;T8: %fadd2 = fadd double %fadd, %c +;T8: +;T8: ret double %fadd2 ;T8: } +; Test for illegal mixing of constrained and non-constrained fp math. +; Test that the order of the instructions does not affect the test. +; CHECK9: Constrained and normal floating-point cannot be mixed in a function! +;T9: define double @f9(double %a, double %b, double %c) #0 { +;T9: entry: +;T9: %fadd = fadd double %a, %c +;T9: +;T9: %fadd2 = call double @llvm.experimental.constrained.fadd.f64( +;T9: double %fadd, double %b, +;T9: metadata !"round.dynamic", +;T9: metadata !"fpexcept.strict") #0 +;T9: +;T9: ret double %fadd2 +;T9: } + +; Test for illegal mixing of constrained and non-constrained fp math. +; Test that truncating instructions are properly tested. +; CHECK10: Constrained and normal floating-point cannot be mixed in a function! +;T10: define float @f10(double %a, float %b) #0 { +;T10: entry: +;T10: %fpval = fptrunc double %a to float; +;T10: +;T10: %fpval2 = call float @llvm.experimental.constrained.fadd.f32( +;T10: float %fpval, float %b, +;T10: metadata !"round.dynamic", +;T10: metadata !"fpexcept.strict") #0 +;T10: +;T10: ret float %fpval2 +;T10: } + +; Test for illegal mixing of constrained and non-constrained fp math. +; Test that extending intructions are properly tested. +; CHECK11: Constrained and normal floating-point cannot be mixed in a function! +;T11: define double @f11(float %a, double %b) #0 { +;T11: entry: +;T11: %fpval = fpext float %a to double; +;T11: +;T11: %fpval2 = call double @llvm.experimental.constrained.fadd.f64( +;T11: double %fpval, double %b, +;T11: metadata !"round.dynamic", +;T11: metadata !"fpexcept.strict") #0 +;T11: +;T11: ret double %fpval2 +;T11: } + +; Test for illegal mixing of constrained and non-constrained fp math. +; Test that fneg operations are NOT tested. +; CHECK12: xxx +;T12: define double @f12(double %a, double %b) #0 { +;T12: entry: +;T12: %fneg = fneg double %a +;T12: +;T12: %fneg2 = call double @llvm.experimental.constrained.fadd.f64( +;T12: double %fneg, double %b, +;T12: metadata !"round.dynamic", +;T12: metadata !"fpexcept.strict") #0 +;T12: +;T12: ret double %fneg2 +;T12: } + + attributes #0 = { strictfp }