diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -140,6 +140,34 @@ } return false; } + + llvm::ConstrainedFPIntrinsic::RoundingMode getConstrainedRounding() const { + switch (FPFeatures.getRoundingMode()) { + case LangOptions::FPRoundingModeKind::ToNearest: + return llvm::ConstrainedFPIntrinsic::RoundingMode::rmToNearest; + case LangOptions::FPRoundingModeKind::Downward: + return llvm:: ConstrainedFPIntrinsic::RoundingMode::rmDownward; + case LangOptions::FPRoundingModeKind::Upward: + return llvm::ConstrainedFPIntrinsic::RoundingMode::rmUpward; + case LangOptions::FPRoundingModeKind::TowardZero: + return llvm::ConstrainedFPIntrinsic::RoundingMode::rmTowardZero; + case LangOptions::FPRoundingModeKind::Dynamic: + return llvm::ConstrainedFPIntrinsic::RoundingMode::rmDynamic; + } + return llvm::ConstrainedFPIntrinsic::RoundingMode::rmDynamic; + } + + llvm::ConstrainedFPIntrinsic::ExceptionBehavior getConstrainedExcept() const { + switch (FPFeatures.getExceptionMode()) { + case LangOptions::FPExceptionModeKind::Ignore: + return llvm::ConstrainedFPIntrinsic::ExceptionBehavior::ebIgnore; + case LangOptions::FPExceptionModeKind::MayTrap: + return llvm::ConstrainedFPIntrinsic::ExceptionBehavior::ebMayTrap; + case LangOptions::FPExceptionModeKind::Strict: + return llvm::ConstrainedFPIntrinsic::ExceptionBehavior::ebStrict; + } + return llvm::ConstrainedFPIntrinsic::ExceptionBehavior::ebStrict; + } }; static bool MustVisitNullValue(const Expr *E) { @@ -728,6 +756,9 @@ return EmitOverflowCheckedBinOp(Ops); if (Ops.LHS->getType()->isFPOrFPVectorTy()) { + CGBuilderTy::FloatingPointStateSaver S(Builder, + Ops.FPFeatures.isFPConstrained(), Ops.getConstrainedExcept(), + Ops.getConstrainedRounding()); Value *V = Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul"); return propagateFMFlags(V, Ops); } @@ -3001,6 +3032,9 @@ } if (Ops.LHS->getType()->isFPOrFPVectorTy()) { + CGBuilderTy::FloatingPointStateSaver S(Builder, + Ops.FPFeatures.isFPConstrained(), Ops.getConstrainedExcept(), + Ops.getConstrainedRounding()); llvm::Value *Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div"); if (CGF.getLangOpts().OpenCL && !CGF.CGM.getCodeGenOpts().CorrectlyRoundedDivSqrt) { @@ -3358,6 +3392,9 @@ if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder)) return FMulAdd; + CGBuilderTy::FloatingPointStateSaver S(Builder, + op.FPFeatures.isFPConstrained(), op.getConstrainedExcept(), + op.getConstrainedRounding()); Value *V = Builder.CreateFAdd(op.LHS, op.RHS, "add"); return propagateFMFlags(V, op); } @@ -3502,6 +3539,9 @@ // Try to form an fmuladd. if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true)) return FMulAdd; + CGBuilderTy::FloatingPointStateSaver S(Builder, + op.FPFeatures.isFPConstrained(), op.getConstrainedExcept(), + op.getConstrainedRounding()); Value *V = Builder.CreateFSub(op.LHS, op.RHS, "sub"); return propagateFMFlags(V, op); } diff --git a/clang/test/CodeGen/pragma-fp-2.cpp b/clang/test/CodeGen/pragma-fp-2.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/pragma-fp-2.cpp @@ -0,0 +1,104 @@ +// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s + +void func_01(float x, float y) { +#pragma clang fp rounding(upward) exceptions(maytrap) + float z = x + y; +// CHECK-LABEL: _Z7func_01ff +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap") +} + +void func_02(float x, float y) { + float z = x + y; +// CHECK-LABEL: _Z7func_02ff +// CHECK: fadd float %0, %1 +} + +void func_03(float x, float y) { + float z1 = x + y; + { + #pragma clang fp rounding(downward) exceptions(strict) + float z2 = x - y; + } + float z3 = x * y; +// CHECK-LABEL: _Z7func_03ff +// CHECK: fadd float +// CHECK: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.downward", metadata !"fpexcept.strict") +// CHECK: fmul float +} + +void func_03a(float x, float y) { + float z1 = x + y; + { + #pragma clang fp rounding(downward) exceptions(strict) + float z2 = x - y; + { + #pragma clang fp rounding(upward) exceptions(maytrap) + float z2a = x * y; + } + float z2b = x + y; + } + float z3 = x * y; +// CHECK-LABEL: _Z8func_03aff +// CHECK: fadd +// CHECK: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.downward", metadata !"fpexcept.strict") +// CHECK: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap") +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.downward", metadata !"fpexcept.strict") +// CHECK: fmul +} + + +#pragma clang fp rounding(towardzero) exceptions(ignore) + +void func_04(float x, float y) { + float z = x + y; +// CHECK-LABEL: _Z7func_04ff +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore") +} + +void func_05(float x, float y) { + float z = x / y; +// CHECK-LABEL: _Z7func_05ff +// CHECK: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore") +} + +#pragma clang fp rounding(dynamic) exceptions(maytrap) + +void func_06(float x, float y) { + float z = x + y; +// CHECK-LABEL: _Z7func_06ff +// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap") +} + +#pragma clang fp rounding(tonearest) exceptions(ignore) + +void func_07(float x, float y) { + float z = x + y; +// CHECK-LABEL: _Z7func_07ff +// CHECK: fadd float +} + +template +T tfunc_08(T a, T b) { + #pragma clang fp rounding(downward) + return a * b; +} + +float func_09(float x, float y) { + return x + y; +// CHECK-LABEL: _Z7func_09ff +// CHECK: fadd float +} + +float func_10(float x, float y) { + return tfunc_08(x, y); +// CHECK-LABEL: _Z7func_10ff +} + +// CHECK-LABEL: _Z8tfunc_08IfET_S0_S0_ +// CHECK: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.downward", metadata !"fpexcept.ignore") + +float func_11(float x, float y) { + return x - y; +// CHECK-LABEL: _Z7func_11ff +// CHECK: fsub float +}