diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -252,6 +252,7 @@ ComplexPairTy LHS; ComplexPairTy RHS; QualType Ty; // Computation Type. + FPOptions FPFeatures; }; BinOpInfo EmitBinOps(const BinaryOperator *E, @@ -643,6 +644,7 @@ llvm::Value *ResR, *ResI; if (Op.LHS.first->getType()->isFloatingPointTy()) { + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures); ResR = Builder.CreateFAdd(Op.LHS.first, Op.RHS.first, "add.r"); if (Op.LHS.second && Op.RHS.second) ResI = Builder.CreateFAdd(Op.LHS.second, Op.RHS.second, "add.i"); @@ -661,6 +663,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinSub(const BinOpInfo &Op) { llvm::Value *ResR, *ResI; if (Op.LHS.first->getType()->isFloatingPointTy()) { + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures); ResR = Builder.CreateFSub(Op.LHS.first, Op.RHS.first, "sub.r"); if (Op.LHS.second && Op.RHS.second) ResI = Builder.CreateFSub(Op.LHS.second, Op.RHS.second, "sub.i"); @@ -753,6 +756,7 @@ // FIXME: C11 also provides for imaginary types which would allow folding // still more of this within the type system. + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures); if (Op.LHS.second && Op.RHS.second) { // If both operands are complex, emit the core math directly, and then // test for NaNs. If we find NaNs in the result, we delegate to a libcall @@ -854,6 +858,7 @@ // // FIXME: We would be able to avoid the libcall in many places if we // supported imaginary types in addition to complex types. + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures); if (RHSi && !CGF.getLangOpts().FastMath) { BinOpInfo LibCallOp = Op; // If LHS was a real, supply a null imaginary part. @@ -1025,6 +1030,7 @@ Ops.Ty = PromotionType; else Ops.Ty = E->getType(); + Ops.FPFeatures = E->getFPFeaturesInEffect(CGF.getLangOpts()); return Ops; } @@ -1039,8 +1045,9 @@ if (const AtomicType *AT = LHSTy->getAs()) LHSTy = AT->getValueType(); - CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E); BinOpInfo OpInfo; + OpInfo.FPFeatures = E->getFPFeaturesInEffect(CGF.getLangOpts()); + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, OpInfo.FPFeatures); // Load the RHS and LHS operands. // __block variables need to have the rhs evaluated first, plus this should diff --git a/clang/test/CodeGen/complex-strictfp.c b/clang/test/CodeGen/complex-strictfp.c --- a/clang/test/CodeGen/complex-strictfp.c +++ b/clang/test/CodeGen/complex-strictfp.c @@ -5,8 +5,8 @@ // Test that the constrained intrinsics are picking up the exception // metadata from the AST instead of the global default from the command line. // Include rounding metadata in the testing. -// FIXME: All cases of "fpexcept.maytrap" in this test are wrong. -// FIXME: All cases of "round.tonearest" in this test are wrong. +// Any cases of "fpexcept.maytrap" in this test are clang bugs. +// Any cases of "round.tonearest" in this test are clang bugs. #pragma float_control(except, on) #pragma STDC FENV_ROUND FE_UPWARD @@ -15,7 +15,7 @@ _Complex float cf; double D; -// CHECK-LABEL: define {{[^@]+}}@test3a( +// CHECK-LABEL: @test3a( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = load double, ptr @D, align 8 // CHECK-NEXT: [[CF_REAL:%.*]] = load float, ptr @cf, align 4 @@ -33,7 +33,7 @@ cf += D; } -// CHECK-LABEL: define {{[^@]+}}@test3b( +// CHECK-LABEL: @test3b( // CHECK-NEXT: entry: // CHECK-NEXT: [[CF_REAL:%.*]] = load float, ptr @cf, align 4 // CHECK-NEXT: [[CF_IMAG:%.*]] = load float, ptr getelementptr inbounds ({ float, float }, ptr @cf, i32 0, i32 1), align 4 @@ -48,7 +48,7 @@ D += cf; } -// CHECK-LABEL: define {{[^@]+}}@test3c( +// CHECK-LABEL: @test3c( // CHECK-NEXT: entry: // CHECK-NEXT: [[G1_REAL:%.*]] = load double, ptr @g1, align 8 // CHECK-NEXT: [[G1_IMAG:%.*]] = load double, ptr getelementptr inbounds ({ double, double }, ptr @g1, i32 0, i32 1), align 8 @@ -69,12 +69,12 @@ cf /= g1; } -// CHECK-LABEL: define {{[^@]+}}@test3d( +// CHECK-LABEL: @test3d( // CHECK-NEXT: entry: // CHECK-NEXT: [[G1_REAL:%.*]] = load double, ptr @g1, align 8 // CHECK-NEXT: [[G1_IMAG:%.*]] = load double, ptr getelementptr inbounds ({ double, double }, ptr @g1, i32 0, i32 1), align 8 // CHECK-NEXT: [[TMP0:%.*]] = load double, ptr @D, align 8 -// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[G1_REAL]], double [[TMP0]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") #[[ATTR2]] +// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[G1_REAL]], double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]] // CHECK-NEXT: store double [[ADD_R]], ptr @g1, align 8 // CHECK-NEXT: store double [[G1_IMAG]], ptr getelementptr inbounds ({ double, double }, ptr @g1, i32 0, i32 1), align 8 // CHECK-NEXT: ret void @@ -83,12 +83,12 @@ g1 = g1 + D; } -// CHECK-LABEL: define {{[^@]+}}@test3e( +// CHECK-LABEL: @test3e( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = load double, ptr @D, align 8 // CHECK-NEXT: [[G1_REAL:%.*]] = load double, ptr @g1, align 8 // CHECK-NEXT: [[G1_IMAG:%.*]] = load double, ptr getelementptr inbounds ({ double, double }, ptr @g1, i32 0, i32 1), align 8 -// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[TMP0]], double [[G1_REAL]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") #[[ATTR2]] +// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[TMP0]], double [[G1_REAL]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]] // CHECK-NEXT: store double [[ADD_R]], ptr @g1, align 8 // CHECK-NEXT: store double [[G1_IMAG]], ptr getelementptr inbounds ({ double, double }, ptr @g1, i32 0, i32 1), align 8 // CHECK-NEXT: ret void @@ -97,7 +97,7 @@ g1 = D + g1; } -// CHECK-LABEL: define {{[^@]+}}@t1( +// CHECK-LABEL: @t1( // CHECK-NEXT: entry: // CHECK-NEXT: [[CONV:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double 4.000000e+00, metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]] // CHECK-NEXT: store float [[CONV]], ptr @cf, align 4 @@ -107,7 +107,7 @@ (__real__ cf) = 4.0; } -// CHECK-LABEL: define {{[^@]+}}@t2( +// CHECK-LABEL: @t2( // CHECK-NEXT: entry: // CHECK-NEXT: [[CONV:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double 4.000000e+00, metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]] // CHECK-NEXT: store float [[CONV]], ptr getelementptr inbounds ({ float, float }, ptr @cf, i32 0, i32 1), align 4 @@ -117,7 +117,7 @@ (__imag__ cf) = 4.0; } -// CHECK-LABEL: define {{[^@]+}}@t91( +// CHECK-LABEL: @t91( // CHECK-NEXT: entry: // CHECK-NEXT: [[C:%.*]] = alloca [0 x i8], align 1 // CHECK-NEXT: br i1 false, label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] @@ -139,7 +139,7 @@ (0 ? 2.0f : (_Complex double) 2.0f); } -// CHECK-LABEL: define {{[^@]+}}@t92( +// CHECK-LABEL: @t92( // CHECK-NEXT: entry: // CHECK-NEXT: [[C:%.*]] = alloca [0 x i8], align 1 // CHECK-NEXT: br i1 false, label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]