diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -14526,6 +14526,7 @@ llvm::Type *ResultType = ConvertType(E->getType()); Value *X = EmitScalarExpr(E->getArg(0)); if (Builder.getIsFPConstrained()) { + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); llvm::Function *F = CGM.getIntrinsic( Intrinsic::experimental_constrained_sqrt, ResultType); return Builder.CreateConstrainedFPCall(F, X); @@ -14670,8 +14671,13 @@ ? Intrinsic::experimental_constrained_trunc : Intrinsic::trunc; llvm::Function *F = CGM.getIntrinsic(ID, ResultType); - return Builder.getIsFPConstrained() ? Builder.CreateConstrainedFPCall(F, X) - : Builder.CreateCall(F, X); + if (Builder.getIsFPConstrained()) { + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); + return Builder.CreateConstrainedFPCall(F, X); + } + else { + return Builder.CreateCall(F, X); + } } // Absolute value @@ -14704,35 +14710,47 @@ switch (BuiltinID) { case PPC::BI__builtin_vsx_xvmaddadp: case PPC::BI__builtin_vsx_xvmaddasp: - if (Builder.getIsFPConstrained()) + if (Builder.getIsFPConstrained()) { + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); return Builder.CreateConstrainedFPCall(F, {X, Y, Z}); - else + } + else { return Builder.CreateCall(F, {X, Y, Z}); + } case PPC::BI__builtin_vsx_xvnmaddadp: case PPC::BI__builtin_vsx_xvnmaddasp: - if (Builder.getIsFPConstrained()) + if (Builder.getIsFPConstrained()) { + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); return Builder.CreateFNeg( Builder.CreateConstrainedFPCall(F, {X, Y, Z}), "neg"); - else + } + else { return Builder.CreateFNeg(Builder.CreateCall(F, {X, Y, Z}), "neg"); + } case PPC::BI__builtin_vsx_xvmsubadp: case PPC::BI__builtin_vsx_xvmsubasp: - if (Builder.getIsFPConstrained()) + if (Builder.getIsFPConstrained()) { + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); return Builder.CreateConstrainedFPCall( F, {X, Y, Builder.CreateFNeg(Z, "neg")}); - else + } + else { return Builder.CreateCall(F, {X, Y, Builder.CreateFNeg(Z, "neg")}); + } case PPC::BI__builtin_vsx_xvnmsubadp: case PPC::BI__builtin_vsx_xvnmsubasp: - if (Builder.getIsFPConstrained()) + if (Builder.getIsFPConstrained()) { + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); return Builder.CreateFNeg( Builder.CreateConstrainedFPCall( F, {X, Y, Builder.CreateFNeg(Z, "neg")}), "neg"); - else + } + else { return Builder.CreateFNeg( Builder.CreateCall(F, {X, Y, Builder.CreateFNeg(Z, "neg")}), "neg"); + } } llvm_unreachable("Unknown FMA operation"); return nullptr; // Suppress no-return warning diff --git a/clang/test/CodeGen/builtins-ppc-fma.c b/clang/test/CodeGen/builtins-ppc-fma.c --- a/clang/test/CodeGen/builtins-ppc-fma.c +++ b/clang/test/CodeGen/builtins-ppc-fma.c @@ -1,6 +1,17 @@ // RUN: %clang_cc1 -triple powerpc64le-gnu-linux \ -// RUN: -target-feature +altivec -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck \ +// RUN: -target-feature +altivec -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck --check-prefix=NOSTRICT --check-prefix=SHARED \ // RUN: %s +// RUN: %clang_cc1 -triple powerpc64le-gnu-linux \ +// RUN: -ffp-exception-behavior=maytrap -DSTRICT=1 \ +// RUN: -target-feature +altivec -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck --check-prefix=STRICT --check-prefix=SHARED \ +// RUN: %s + +#ifdef STRICT +// Test that the constrained intrinsics are picking up the exception +// metadata from the AST instead of the global default from the command line. + +#pragma float_control(except, on) +#endif typedef __attribute__((vector_size(4 * sizeof(float)))) float vec_float; typedef __attribute__((vector_size(2 * sizeof(double)))) double vec_double; @@ -10,34 +21,42 @@ void test_fma(void) { vf = __builtin_vsx_xvmaddasp(vf, vf, vf); - // CHECK: @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}}) + // NOSTRICT: @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}}) + // STRICT: @llvm.experimental.constrained.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") vd = __builtin_vsx_xvmaddadp(vd, vd, vd); - // CHECK: @llvm.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}}) + // NOSTRICT: @llvm.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}}) + // STRICT: @llvm.experimental.constrained.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") vf = __builtin_vsx_xvnmaddasp(vf, vf, vf); - // CHECK: [[RESULT:%[^ ]+]] = call <4 x float> @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}}) - // CHECK: fneg <4 x float> [[RESULT]] + // NOSTRICT: [[RESULT:%[^ ]+]] = call <4 x float> @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}}) + // STRICT: [[RESULT:%[^ ]+]] = call <4 x float> @llvm.experimental.constrained.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") + // SHARED: fneg <4 x float> [[RESULT]] vd = __builtin_vsx_xvnmaddadp(vd, vd, vd); - // CHECK: [[RESULT:%[^ ]+]] = call <2 x double> @llvm.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}}) - // CHECK: fneg <2 x double> [[RESULT]] + // NOSTRICT: [[RESULT:%[^ ]+]] = call <2 x double> @llvm.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}}) + // STRICT: [[RESULT:%[^ ]+]] = call <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict") + // SHARED: fneg <2 x double> [[RESULT]] vf = __builtin_vsx_xvmsubasp(vf, vf, vf); - // CHECK: [[RESULT:%[^ ]+]] = fneg <4 x float> %{{.*}} - // CHECK: @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> [[RESULT]]) + // SHARED: [[RESULT:%[^ ]+]] = fneg <4 x float> %{{.*}} + // NOSTRICT: @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> [[RESULT]]) + // STRICT: @llvm.experimental.constrained.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> [[RESULT]], metadata !"round.tonearest", metadata !"fpexcept.strict") vd = __builtin_vsx_xvmsubadp(vd, vd, vd); - // CHECK: [[RESULT:%[^ ]+]] = fneg <2 x double> %{{.*}} - // CHECK: <2 x double> @llvm.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> [[RESULT]]) + // SHARED: [[RESULT:%[^ ]+]] = fneg <2 x double> %{{.*}} + // NOSTRICT: <2 x double> @llvm.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> [[RESULT]]) + // STRICT: <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> [[RESULT]], metadata !"round.tonearest", metadata !"fpexcept.strict") vf = __builtin_vsx_xvnmsubasp(vf, vf, vf); - // CHECK: [[RESULT:%[^ ]+]] = fneg <4 x float> %{{.*}} - // CHECK: [[RESULT2:%[^ ]+]] = call <4 x float> @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> [[RESULT]]) - // CHECK: fneg <4 x float> [[RESULT2]] + // SHARED: [[RESULT:%[^ ]+]] = fneg <4 x float> %{{.*}} + // NOSTRICT: [[RESULT2:%[^ ]+]] = call <4 x float> @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> [[RESULT]]) + // STRICT: [[RESULT2:%[^ ]+]] = call <4 x float> @llvm.experimental.constrained.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> [[RESULT]], metadata !"round.tonearest", metadata !"fpexcept.strict") + // SHARED: fneg <4 x float> [[RESULT2]] vd = __builtin_vsx_xvnmsubadp(vd, vd, vd); - // CHECK: [[RESULT:%[^ ]+]] = fneg <2 x double> %{{.*}} - // CHECK: [[RESULT2:%[^ ]+]] = call <2 x double> @llvm.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> [[RESULT]]) - // CHECK: fneg <2 x double> [[RESULT2]] + // SHARED: [[RESULT:%[^ ]+]] = fneg <2 x double> %{{.*}} + // NOSTRICT: [[RESULT2:%[^ ]+]] = call <2 x double> @llvm.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> [[RESULT]]) + // STRICT: [[RESULT2:%[^ ]+]] = call <2 x double> @llvm.experimental.constrained.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> [[RESULT]], metadata !"round.tonearest", metadata !"fpexcept.strict") + // SHARED: fneg <2 x double> [[RESULT2]] } diff --git a/clang/test/CodeGen/builtins-ppc-fpconstrained.c b/clang/test/CodeGen/builtins-ppc-fpconstrained.c --- a/clang/test/CodeGen/builtins-ppc-fpconstrained.c +++ b/clang/test/CodeGen/builtins-ppc-fpconstrained.c @@ -2,16 +2,23 @@ // RUN: %clang_cc1 -triple powerpc64le-gnu-linux -target-feature +vsx \ // RUN: -emit-llvm %s -o - | FileCheck --check-prefix=CHECK-UNCONSTRAINED %s // RUN: %clang_cc1 -triple powerpc64le-gnu-linux -target-feature +vsx \ -// RUN: -ffp-exception-behavior=strict -emit-llvm %s -o - | FileCheck \ -// RUN: --check-prefix=CHECK-CONSTRAINED -vv %s +// RUN: -ffp-exception-behavior=maytrap -DSTRICT=1 -emit-llvm %s -o - | \ +// RUN: FileCheck --check-prefix=CHECK-CONSTRAINED -vv %s // RUN: %clang_cc1 -triple powerpc64le-gnu-linux -target-feature +vsx \ // RUN: -fallow-half-arguments-and-returns -S -o - %s | \ // RUN: FileCheck --check-prefix=CHECK-ASM --check-prefix=NOT-FIXME-CHECK %s // RUN: %clang_cc1 -triple powerpc64le-gnu-linux -target-feature +vsx \ -// RUN: -fallow-half-arguments-and-returns -S -ffp-exception-behavior=strict \ -// RUN: -o - %s | FileCheck --check-prefix=CHECK-ASM \ +// RUN: -fallow-half-arguments-and-returns -S -ffp-exception-behavior=maytrap \ +// RUN: -DSTRICT=1 -o - %s | FileCheck --check-prefix=CHECK-ASM \ // RUN: --check-prefix=FIXME-CHECK %s +#ifdef STRICT +// Test that the constrained intrinsics are picking up the exception +// metadata from the AST instead of the global default from the command line. + +#pragma float_control(except, on) +#endif + typedef __attribute__((vector_size(4 * sizeof(float)))) float vec_float; typedef __attribute__((vector_size(2 * sizeof(double)))) double vec_double;