mibintc updated this revision to Diff 244894.
mibintc added a comment.
I found the problem in the #pragma float_control (push/pop) stack, it was just
a dumb bug.
I also added -include-pch test cases, and added code to ASTWriter ASTReader to
preserve the floatcontrol pragma stack
For 2 of the new floatcontrol test cases, I temporarily added XFAIL because the
patch to default -ffp-precise=fast and ffp-contract=on has been withdrawn (will
re-commit soon).
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D72841/new/
https://reviews.llvm.org/D72841
Files:
clang/docs/LanguageExtensions.rst
clang/include/clang/AST/Stmt.h
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Basic/LangOptions.def
clang/include/clang/Basic/LangOptions.h
clang/include/clang/Basic/PragmaKinds.h
clang/include/clang/Basic/TokenKinds.def
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/Sema.h
clang/include/clang/Serialization/ASTBitCodes.h
clang/include/clang/Serialization/ASTReader.h
clang/include/clang/Serialization/ASTWriter.h
clang/lib/CodeGen/CGExprScalar.cpp
clang/lib/CodeGen/CodeGenFunction.cpp
clang/lib/CodeGen/CodeGenFunction.h
clang/lib/Frontend/CompilerInvocation.cpp
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Parse/ParsePragma.cpp
clang/lib/Parse/ParseStmt.cpp
clang/lib/Parse/Parser.cpp
clang/lib/Sema/Sema.cpp
clang/lib/Sema/SemaAttr.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaStmt.cpp
clang/lib/Serialization/ASTReader.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/test/CodeGen/constrained-math-builtins.c
clang/test/CodeGen/fast-math.c
clang/test/CodeGen/fp-contract-on-pragma.cpp
clang/test/CodeGen/fp-contract-pragma.cpp
clang/test/CodeGen/fp-floatcontrol-class.cpp
clang/test/CodeGen/fp-floatcontrol-pragma.cpp
clang/test/CodeGen/fp-floatcontrol-stack.cpp
clang/test/CodeGen/fpconstrained.c
clang/test/CodeGen/fpconstrained.cpp
clang/test/CodeGenOpenCL/builtins-amdgcn-dl-insts.cl
clang/test/CodeGenOpenCL/builtins-amdgcn-gfx9.cl
clang/test/CodeGenOpenCL/builtins-amdgcn-interp.cl
clang/test/CodeGenOpenCL/builtins-amdgcn-mfma.cl
clang/test/CodeGenOpenCL/builtins-amdgcn-vi.cl
clang/test/CodeGenOpenCL/builtins-amdgcn.cl
clang/test/CodeGenOpenCL/builtins-f16.cl
clang/test/CodeGenOpenCL/builtins-r600.cl
clang/test/CodeGenOpenCL/relaxed-fpmath.cl
clang/test/CodeGenOpenCL/single-precision-constant.cl
clang/test/PCH/pragma-floatcontrol.c
clang/test/Parser/fp-floatcontrol-syntax.cpp
llvm/include/llvm/IR/IRBuilder.h
Index: llvm/include/llvm/IR/IRBuilder.h
===================================================================
--- llvm/include/llvm/IR/IRBuilder.h
+++ llvm/include/llvm/IR/IRBuilder.h
@@ -215,6 +215,8 @@
/// Get the flags to be applied to created floating point ops
FastMathFlags getFastMathFlags() const { return FMF; }
+ FastMathFlags& getFastMathFlags() { return FMF; }
+
/// Clear the fast-math flags.
void clearFastMathFlags() { FMF.clear(); }
@@ -299,10 +301,16 @@
IRBuilderBase &Builder;
FastMathFlags FMF;
MDNode *FPMathTag;
+ bool IsFPConstrained;
+ fp::ExceptionBehavior DefaultConstrainedExcept;
+ fp::RoundingMode DefaultConstrainedRounding;
public:
FastMathFlagGuard(IRBuilderBase &B)
- : Builder(B), FMF(B.FMF), FPMathTag(B.DefaultFPMathTag) {}
+ : Builder(B), FMF(B.FMF), FPMathTag(B.DefaultFPMathTag),
+ IsFPConstrained(B.IsFPConstrained),
+ DefaultConstrainedExcept(B.DefaultConstrainedExcept),
+ DefaultConstrainedRounding(B.DefaultConstrainedRounding) {}
FastMathFlagGuard(const FastMathFlagGuard &) = delete;
FastMathFlagGuard &operator=(const FastMathFlagGuard &) = delete;
@@ -310,6 +318,9 @@
~FastMathFlagGuard() {
Builder.FMF = FMF;
Builder.DefaultFPMathTag = FPMathTag;
+ Builder.IsFPConstrained = IsFPConstrained;
+ Builder.DefaultConstrainedExcept = DefaultConstrainedExcept;
+ Builder.DefaultConstrainedRounding = DefaultConstrainedRounding;
}
};
Index: clang/test/Parser/fp-floatcontrol-syntax.cpp
===================================================================
--- /dev/null
+++ clang/test/Parser/fp-floatcontrol-syntax.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -DCHECK_ERROR %s
+
+float function_scope(float a) {
+# pragma float_control(precise, on) junk // expected-warning {{extra tokens at end of '#pragma float_control' - ignored}}
+ return a;
+}
+
+#ifdef CHECK_ERROR
+# pragma float_control(push)
+# pragma float_control(pop)
+# pragma float_control(precise,on,push)
+void check_stack() {
+#pragma float_control(push) // expected-error {{can only appear at file scope}}
+#pragma float_control(pop) // expected-error {{can only appear at file scope}}
+#pragma float_control(precise,on,push) // expected-error {{can only appear at file scope}}
+#pragma float_control(except,on,push) // expected-error {{can only appear at file scope}}
+#pragma float_control(except,on,push,junk) // expected-error {{float_control is malformed}}
+ return;
+}
+#endif
Index: clang/test/PCH/pragma-floatcontrol.c
===================================================================
--- /dev/null
+++ clang/test/PCH/pragma-floatcontrol.c
@@ -0,0 +1,55 @@
+// Test this without pch.
+// RUN: %clang_cc1 %s -include %s -verify -fsyntax-only -DSET
+// RUN: %clang_cc1 %s -include %s -verify -fsyntax-only -DPUSH
+// RUN: %clang_cc1 %s -include %s -verify -fsyntax-only -DPUSH_POP
+
+// Test with pch.
+// RUN: %clang_cc1 %s -DSET -emit-pch -o %t
+// RUN: %clang_cc1 %s -DSET -include-pch %t -emit-llvm -o - | FileCheck --check-prefix=CHECK-EBSTRICT %s
+// RUN: %clang_cc1 %s -DPUSH -emit-pch -o %t
+// RUN: %clang_cc1 %s -DPUSH -verify -include-pch %t
+// RUN: %clang_cc1 %s -DPUSH_POP -emit-pch -o %t
+// RUN: %clang_cc1 %s -DPUSH_POP -verify -include-pch %t
+
+#ifndef HEADER
+#define HEADER
+
+#ifdef SET
+#pragma float_control(except, on)
+#endif
+
+#ifdef PUSH
+#pragma float_control(precise, on)
+#pragma float_control (push)
+#pragma float_control(precise, off)
+#endif
+
+#ifdef PUSH_POP
+#pragma float_control (precise, on, push)
+#pragma float_control (push)
+#pragma float_control (pop)
+#endif
+#else
+
+#ifdef SET
+float fun(float a, float b) {
+// CHECK-LABEL: define float @fun{{.*}}
+//CHECK-EBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict
+//CHECK-EBSTRICT: llvm.experimental.constrained.fadd{{.*}}tonearest{{.*}}strict
+ return a*b + 2;
+}
+#pragma float_control(pop) // expected-warning {{#pragma float_control(pop, ...) failed: stack empty}}
+#pragma float_control(pop) // expected-warning {{#pragma float_control(pop, ...) failed: stack empty}}
+#endif
+
+#ifdef PUSH
+#pragma float_control(pop)
+#pragma float_control(pop) // expected-warning {{#pragma float_control(pop, ...) failed: stack empty}}
+#endif
+
+#ifdef PUSH_POP
+#pragma float_control(pop)
+#pragma float_control(pop) // expected-warning {{#pragma float_control(pop, ...) failed: stack empty}}
+#endif
+
+#endif //ifndef HEADER
Index: clang/test/CodeGenOpenCL/single-precision-constant.cl
===================================================================
--- clang/test/CodeGenOpenCL/single-precision-constant.cl
+++ clang/test/CodeGenOpenCL/single-precision-constant.cl
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 %s -cl-single-precision-constant -emit-llvm -o - | FileCheck %s
float fn(float f) {
- // CHECK: tail call float @llvm.fmuladd.f32(float %f, float 2.000000e+00, float 1.000000e+00)
+ // CHECK: tail call contract float @llvm.fmuladd.f32(float %f, float 2.000000e+00, float 1.000000e+00)
return f*2. + 1.;
}
Index: clang/test/CodeGenOpenCL/relaxed-fpmath.cl
===================================================================
--- clang/test/CodeGenOpenCL/relaxed-fpmath.cl
+++ clang/test/CodeGenOpenCL/relaxed-fpmath.cl
@@ -8,12 +8,12 @@
float spscalardiv(float a, float b) {
// CHECK: @spscalardiv(
- // NORMAL: fdiv float
+ // NORMAL: fdiv contract float
// FAST: fdiv fast float
- // FINITE: fdiv nnan ninf float
- // UNSAFE: fdiv nnan nsz float
- // MAD: fdiv float
- // NOSIGNED: fdiv nsz float
+ // FINITE: fdiv nnan ninf contract float
+ // UNSAFE: fdiv nnan nsz contract float
+ // MAD: fdiv contract float
+ // NOSIGNED: fdiv nsz contract float
return a / b;
}
// CHECK: attributes
Index: clang/test/CodeGenOpenCL/builtins-r600.cl
===================================================================
--- clang/test/CodeGenOpenCL/builtins-r600.cl
+++ clang/test/CodeGenOpenCL/builtins-r600.cl
@@ -2,7 +2,7 @@
// RUN: %clang_cc1 -triple r600-unknown-unknown -target-cpu cypress -S -emit-llvm -o - %s | FileCheck %s
// CHECK-LABEL: @test_recipsqrt_ieee_f32
-// CHECK: call float @llvm.r600.recipsqrt.ieee.f32
+// CHECK: call contract float @llvm.r600.recipsqrt.ieee.f32
void test_recipsqrt_ieee_f32(global float* out, float a)
{
*out = __builtin_r600_recipsqrt_ieeef(a);
@@ -10,7 +10,7 @@
#if cl_khr_fp64
// XCHECK-LABEL: @test_recipsqrt_ieee_f64
-// XCHECK: call double @llvm.r600.recipsqrt.ieee.f64
+// XCHECK: call contract double @llvm.r600.recipsqrt.ieee.f64
void test_recipsqrt_ieee_f64(global double* out, double a)
{
*out = __builtin_r600_recipsqrt_ieee(a);
Index: clang/test/CodeGenOpenCL/builtins-f16.cl
===================================================================
--- clang/test/CodeGenOpenCL/builtins-f16.cl
+++ clang/test/CodeGenOpenCL/builtins-f16.cl
@@ -6,66 +6,66 @@
void test_half_builtins(half h0, half h1, half h2) {
volatile half res;
- // CHECK: call half @llvm.copysign.f16(half %h0, half %h1)
+ // CHECK: call contract half @llvm.copysign.f16(half %h0, half %h1)
res = __builtin_copysignf16(h0, h1);
- // CHECK: call half @llvm.fabs.f16(half %h0)
+ // CHECK: call contract half @llvm.fabs.f16(half %h0)
res = __builtin_fabsf16(h0);
- // CHECK: call half @llvm.ceil.f16(half %h0)
+ // CHECK: call contract half @llvm.ceil.f16(half %h0)
res = __builtin_ceilf16(h0);
- // CHECK: call half @llvm.cos.f16(half %h0)
+ // CHECK: call contract half @llvm.cos.f16(half %h0)
res = __builtin_cosf16(h0);
- // CHECK: call half @llvm.exp.f16(half %h0)
+ // CHECK: call contract half @llvm.exp.f16(half %h0)
res = __builtin_expf16(h0);
- // CHECK: call half @llvm.exp2.f16(half %h0)
+ // CHECK: call contract half @llvm.exp2.f16(half %h0)
res = __builtin_exp2f16(h0);
- // CHECK: call half @llvm.floor.f16(half %h0)
+ // CHECK: call contract half @llvm.floor.f16(half %h0)
res = __builtin_floorf16(h0);
- // CHECK: call half @llvm.fma.f16(half %h0, half %h1, half %h2)
+ // CHECK: call contract half @llvm.fma.f16(half %h0, half %h1, half %h2)
res = __builtin_fmaf16(h0, h1 ,h2);
- // CHECK: call half @llvm.maxnum.f16(half %h0, half %h1)
+ // CHECK: call contract half @llvm.maxnum.f16(half %h0, half %h1)
res = __builtin_fmaxf16(h0, h1);
- // CHECK: call half @llvm.minnum.f16(half %h0, half %h1)
+ // CHECK: call contract half @llvm.minnum.f16(half %h0, half %h1)
res = __builtin_fminf16(h0, h1);
- // CHECK: frem half %h0, %h1
+ // CHECK: frem contract half %h0, %h1
res = __builtin_fmodf16(h0, h1);
- // CHECK: call half @llvm.pow.f16(half %h0, half %h1)
+ // CHECK: call contract half @llvm.pow.f16(half %h0, half %h1)
res = __builtin_powf16(h0, h1);
- // CHECK: call half @llvm.log10.f16(half %h0)
+ // CHECK: call contract half @llvm.log10.f16(half %h0)
res = __builtin_log10f16(h0);
- // CHECK: call half @llvm.log2.f16(half %h0)
+ // CHECK: call contract half @llvm.log2.f16(half %h0)
res = __builtin_log2f16(h0);
- // CHECK: call half @llvm.log.f16(half %h0)
+ // CHECK: call contract half @llvm.log.f16(half %h0)
res = __builtin_logf16(h0);
- // CHECK: call half @llvm.rint.f16(half %h0)
+ // CHECK: call contract half @llvm.rint.f16(half %h0)
res = __builtin_rintf16(h0);
- // CHECK: call half @llvm.round.f16(half %h0)
+ // CHECK: call contract half @llvm.round.f16(half %h0)
res = __builtin_roundf16(h0);
- // CHECK: call half @llvm.sin.f16(half %h0)
+ // CHECK: call contract half @llvm.sin.f16(half %h0)
res = __builtin_sinf16(h0);
- // CHECK: call half @llvm.sqrt.f16(half %h0)
+ // CHECK: call contract half @llvm.sqrt.f16(half %h0)
res = __builtin_sqrtf16(h0);
- // CHECK: call half @llvm.trunc.f16(half %h0)
+ // CHECK: call contract half @llvm.trunc.f16(half %h0)
res = __builtin_truncf16(h0);
- // CHECK: call half @llvm.canonicalize.f16(half %h0)
+ // CHECK: call contract half @llvm.canonicalize.f16(half %h0)
res = __builtin_canonicalizef16(h0);
}
Index: clang/test/CodeGenOpenCL/builtins-amdgcn.cl
===================================================================
--- clang/test/CodeGenOpenCL/builtins-amdgcn.cl
+++ clang/test/CodeGenOpenCL/builtins-amdgcn.cl
@@ -61,133 +61,133 @@
}
// CHECK-LABEL: @test_div_fmas_f32
-// CHECK: call float @llvm.amdgcn.div.fmas.f32
+// CHECK: call contract float @llvm.amdgcn.div.fmas.f32
void test_div_fmas_f32(global float* out, float a, float b, float c, int d)
{
*out = __builtin_amdgcn_div_fmasf(a, b, c, d);
}
// CHECK-LABEL: @test_div_fmas_f64
-// CHECK: call double @llvm.amdgcn.div.fmas.f64
+// CHECK: call contract double @llvm.amdgcn.div.fmas.f64
void test_div_fmas_f64(global double* out, double a, double b, double c, int d)
{
*out = __builtin_amdgcn_div_fmas(a, b, c, d);
}
// CHECK-LABEL: @test_div_fixup_f32
-// CHECK: call float @llvm.amdgcn.div.fixup.f32
+// CHECK: call contract float @llvm.amdgcn.div.fixup.f32
void test_div_fixup_f32(global float* out, float a, float b, float c)
{
*out = __builtin_amdgcn_div_fixupf(a, b, c);
}
// CHECK-LABEL: @test_div_fixup_f64
-// CHECK: call double @llvm.amdgcn.div.fixup.f64
+// CHECK: call contract double @llvm.amdgcn.div.fixup.f64
void test_div_fixup_f64(global double* out, double a, double b, double c)
{
*out = __builtin_amdgcn_div_fixup(a, b, c);
}
// CHECK-LABEL: @test_trig_preop_f32
-// CHECK: call float @llvm.amdgcn.trig.preop.f32
+// CHECK: call contract float @llvm.amdgcn.trig.preop.f32
void test_trig_preop_f32(global float* out, float a, int b)
{
*out = __builtin_amdgcn_trig_preopf(a, b);
}
// CHECK-LABEL: @test_trig_preop_f64
-// CHECK: call double @llvm.amdgcn.trig.preop.f64
+// CHECK: call contract double @llvm.amdgcn.trig.preop.f64
void test_trig_preop_f64(global double* out, double a, int b)
{
*out = __builtin_amdgcn_trig_preop(a, b);
}
// CHECK-LABEL: @test_rcp_f32
-// CHECK: call float @llvm.amdgcn.rcp.f32
+// CHECK: call contract float @llvm.amdgcn.rcp.f32
void test_rcp_f32(global float* out, float a)
{
*out = __builtin_amdgcn_rcpf(a);
}
// CHECK-LABEL: @test_rcp_f64
-// CHECK: call double @llvm.amdgcn.rcp.f64
+// CHECK: call contract double @llvm.amdgcn.rcp.f64
void test_rcp_f64(global double* out, double a)
{
*out = __builtin_amdgcn_rcp(a);
}
// CHECK-LABEL: @test_rsq_f32
-// CHECK: call float @llvm.amdgcn.rsq.f32
+// CHECK: call contract float @llvm.amdgcn.rsq.f32
void test_rsq_f32(global float* out, float a)
{
*out = __builtin_amdgcn_rsqf(a);
}
// CHECK-LABEL: @test_rsq_f64
-// CHECK: call double @llvm.amdgcn.rsq.f64
+// CHECK: call contract double @llvm.amdgcn.rsq.f64
void test_rsq_f64(global double* out, double a)
{
*out = __builtin_amdgcn_rsq(a);
}
// CHECK-LABEL: @test_rsq_clamp_f32
-// CHECK: call float @llvm.amdgcn.rsq.clamp.f32
+// CHECK: call contract float @llvm.amdgcn.rsq.clamp.f32
void test_rsq_clamp_f32(global float* out, float a)
{
*out = __builtin_amdgcn_rsq_clampf(a);
}
// CHECK-LABEL: @test_rsq_clamp_f64
-// CHECK: call double @llvm.amdgcn.rsq.clamp.f64
+// CHECK: call contract double @llvm.amdgcn.rsq.clamp.f64
void test_rsq_clamp_f64(global double* out, double a)
{
*out = __builtin_amdgcn_rsq_clamp(a);
}
// CHECK-LABEL: @test_sin_f32
-// CHECK: call float @llvm.amdgcn.sin.f32
+// CHECK: call contract float @llvm.amdgcn.sin.f32
void test_sin_f32(global float* out, float a)
{
*out = __builtin_amdgcn_sinf(a);
}
// CHECK-LABEL: @test_cos_f32
-// CHECK: call float @llvm.amdgcn.cos.f32
+// CHECK: call contract float @llvm.amdgcn.cos.f32
void test_cos_f32(global float* out, float a)
{
*out = __builtin_amdgcn_cosf(a);
}
// CHECK-LABEL: @test_log_clamp_f32
-// CHECK: call float @llvm.amdgcn.log.clamp.f32
+// CHECK: call contract float @llvm.amdgcn.log.clamp.f32
void test_log_clamp_f32(global float* out, float a)
{
*out = __builtin_amdgcn_log_clampf(a);
}
// CHECK-LABEL: @test_ldexp_f32
-// CHECK: call float @llvm.amdgcn.ldexp.f32
+// CHECK: call contract float @llvm.amdgcn.ldexp.f32
void test_ldexp_f32(global float* out, float a, int b)
{
*out = __builtin_amdgcn_ldexpf(a, b);
}
// CHECK-LABEL: @test_ldexp_f64
-// CHECK: call double @llvm.amdgcn.ldexp.f64
+// CHECK: call contract double @llvm.amdgcn.ldexp.f64
void test_ldexp_f64(global double* out, double a, int b)
{
*out = __builtin_amdgcn_ldexp(a, b);
}
// CHECK-LABEL: @test_frexp_mant_f32
-// CHECK: call float @llvm.amdgcn.frexp.mant.f32
+// CHECK: call contract float @llvm.amdgcn.frexp.mant.f32
void test_frexp_mant_f32(global float* out, float a)
{
*out = __builtin_amdgcn_frexp_mantf(a);
}
// CHECK-LABEL: @test_frexp_mant_f64
-// CHECK: call double @llvm.amdgcn.frexp.mant.f64
+// CHECK: call contract double @llvm.amdgcn.frexp.mant.f64
void test_frexp_mant_f64(global double* out, double a)
{
*out = __builtin_amdgcn_frexp_mant(a);
@@ -208,14 +208,14 @@
}
// CHECK-LABEL: @test_fract_f32
-// CHECK: call float @llvm.amdgcn.fract.f32
+// CHECK: call contract float @llvm.amdgcn.fract.f32
void test_fract_f32(global int* out, float a)
{
*out = __builtin_amdgcn_fractf(a);
}
// CHECK-LABEL: @test_fract_f64
-// CHECK: call double @llvm.amdgcn.fract.f64
+// CHECK: call contract double @llvm.amdgcn.fract.f64
void test_fract_f64(global int* out, double a)
{
*out = __builtin_amdgcn_fract(a);
@@ -417,25 +417,25 @@
}
// CHECK-LABEL: @test_cubeid(
-// CHECK: call float @llvm.amdgcn.cubeid(float %a, float %b, float %c)
+// CHECK: call contract float @llvm.amdgcn.cubeid(float %a, float %b, float %c)
void test_cubeid(global float* out, float a, float b, float c) {
*out = __builtin_amdgcn_cubeid(a, b, c);
}
// CHECK-LABEL: @test_cubesc(
-// CHECK: call float @llvm.amdgcn.cubesc(float %a, float %b, float %c)
+// CHECK: call contract float @llvm.amdgcn.cubesc(float %a, float %b, float %c)
void test_cubesc(global float* out, float a, float b, float c) {
*out = __builtin_amdgcn_cubesc(a, b, c);
}
// CHECK-LABEL: @test_cubetc(
-// CHECK: call float @llvm.amdgcn.cubetc(float %a, float %b, float %c)
+// CHECK: call contract float @llvm.amdgcn.cubetc(float %a, float %b, float %c)
void test_cubetc(global float* out, float a, float b, float c) {
*out = __builtin_amdgcn_cubetc(a, b, c);
}
// CHECK-LABEL: @test_cubema(
-// CHECK: call float @llvm.amdgcn.cubema(float %a, float %b, float %c)
+// CHECK: call contract float @llvm.amdgcn.cubema(float %a, float %b, float %c)
void test_cubema(global float* out, float a, float b, float c) {
*out = __builtin_amdgcn_cubema(a, b, c);
}
@@ -528,7 +528,7 @@
}
// CHECK-LABEL: @test_fmed3_f32
-// CHECK: call float @llvm.amdgcn.fmed3.f32(
+// CHECK: call contract float @llvm.amdgcn.fmed3.f32(
void test_fmed3_f32(global float* out, float a, float b, float c)
{
*out = __builtin_amdgcn_fmed3f(a, b, c);
@@ -620,7 +620,7 @@
}
// CHECK-LABEL: @test_cvt_pkrtz(
-// CHECK: tail call <2 x half> @llvm.amdgcn.cvt.pkrtz(float %src0, float %src1)
+// CHECK: tail call contract <2 x half> @llvm.amdgcn.cvt.pkrtz(float %src0, float %src1)
kernel void test_cvt_pkrtz(global half2* out, float src0, float src1) {
*out = __builtin_amdgcn_cvt_pkrtz(src0, src1);
}
Index: clang/test/CodeGenOpenCL/builtins-amdgcn-vi.cl
===================================================================
--- clang/test/CodeGenOpenCL/builtins-amdgcn-vi.cl
+++ clang/test/CodeGenOpenCL/builtins-amdgcn-vi.cl
@@ -9,49 +9,49 @@
typedef unsigned long ulong;
// CHECK-LABEL: @test_div_fixup_f16
-// CHECK: call half @llvm.amdgcn.div.fixup.f16
+// CHECK: call contract half @llvm.amdgcn.div.fixup.f16
void test_div_fixup_f16(global half* out, half a, half b, half c)
{
*out = __builtin_amdgcn_div_fixuph(a, b, c);
}
// CHECK-LABEL: @test_rcp_f16
-// CHECK: call half @llvm.amdgcn.rcp.f16
+// CHECK: call contract half @llvm.amdgcn.rcp.f16
void test_rcp_f16(global half* out, half a)
{
*out = __builtin_amdgcn_rcph(a);
}
// CHECK-LABEL: @test_rsq_f16
-// CHECK: call half @llvm.amdgcn.rsq.f16
+// CHECK: call contract half @llvm.amdgcn.rsq.f16
void test_rsq_f16(global half* out, half a)
{
*out = __builtin_amdgcn_rsqh(a);
}
// CHECK-LABEL: @test_sin_f16
-// CHECK: call half @llvm.amdgcn.sin.f16
+// CHECK: call contract half @llvm.amdgcn.sin.f16
void test_sin_f16(global half* out, half a)
{
*out = __builtin_amdgcn_sinh(a);
}
// CHECK-LABEL: @test_cos_f16
-// CHECK: call half @llvm.amdgcn.cos.f16
+// CHECK: call contract half @llvm.amdgcn.cos.f16
void test_cos_f16(global half* out, half a)
{
*out = __builtin_amdgcn_cosh(a);
}
// CHECK-LABEL: @test_ldexp_f16
-// CHECK: call half @llvm.amdgcn.ldexp.f16
+// CHECK: call contract half @llvm.amdgcn.ldexp.f16
void test_ldexp_f16(global half* out, half a, int b)
{
*out = __builtin_amdgcn_ldexph(a, b);
}
// CHECK-LABEL: @test_frexp_mant_f16
-// CHECK: call half @llvm.amdgcn.frexp.mant.f16
+// CHECK: call contract half @llvm.amdgcn.frexp.mant.f16
void test_frexp_mant_f16(global half* out, half a)
{
*out = __builtin_amdgcn_frexp_manth(a);
@@ -65,7 +65,7 @@
}
// CHECK-LABEL: @test_fract_f16
-// CHECK: call half @llvm.amdgcn.fract.f16
+// CHECK: call contract half @llvm.amdgcn.fract.f16
void test_fract_f16(global half* out, half a)
{
*out = __builtin_amdgcn_fracth(a);
@@ -107,19 +107,19 @@
}
// CHECK-LABEL: @test_ds_fadd
-// CHECK: call float @llvm.amdgcn.ds.fadd(float addrspace(3)* %out, float %src, i32 0, i32 0, i1 false)
+// CHECK: call contract float @llvm.amdgcn.ds.fadd(float addrspace(3)* %out, float %src, i32 0, i32 0, i1 false)
void test_ds_faddf(local float *out, float src) {
*out = __builtin_amdgcn_ds_faddf(out, src, 0, 0, false);
}
// CHECK-LABEL: @test_ds_fmin
-// CHECK: call float @llvm.amdgcn.ds.fmin(float addrspace(3)* %out, float %src, i32 0, i32 0, i1 false)
+// CHECK: call contract float @llvm.amdgcn.ds.fmin(float addrspace(3)* %out, float %src, i32 0, i32 0, i1 false)
void test_ds_fminf(local float *out, float src) {
*out = __builtin_amdgcn_ds_fminf(out, src, 0, 0, false);
}
// CHECK-LABEL: @test_ds_fmax
-// CHECK: call float @llvm.amdgcn.ds.fmax(float addrspace(3)* %out, float %src, i32 0, i32 0, i1 false)
+// CHECK: call contract float @llvm.amdgcn.ds.fmax(float addrspace(3)* %out, float %src, i32 0, i32 0, i1 false)
void test_ds_fmaxf(local float *out, float src) {
*out = __builtin_amdgcn_ds_fmaxf(out, src, 0, 0, false);
}
Index: clang/test/CodeGenOpenCL/builtins-amdgcn-mfma.cl
===================================================================
--- clang/test/CodeGenOpenCL/builtins-amdgcn-mfma.cl
+++ clang/test/CodeGenOpenCL/builtins-amdgcn-mfma.cl
@@ -20,70 +20,70 @@
// CHECK-LABEL: @test_mfma_f32_32x32x1f32
-// CHECK: call <32 x float> @llvm.amdgcn.mfma.f32.32x32x1f32(float %a, float %b, <32 x float> %c, i32 0, i32 0, i32 0)
+// CHECK: call contract <32 x float> @llvm.amdgcn.mfma.f32.32x32x1f32(float %a, float %b, <32 x float> %c, i32 0, i32 0, i32 0)
void test_mfma_f32_32x32x1f32(global v32f* out, float a, float b, v32f c)
{
*out = __builtin_amdgcn_mfma_f32_32x32x1f32(a, b, c, 0, 0, 0);
}
// CHECK-LABEL: @test_mfma_f32_16x16x1f32
-// CHECK: call <16 x float> @llvm.amdgcn.mfma.f32.16x16x1f32(float %a, float %b, <16 x float> %c, i32 0, i32 0, i32 0)
+// CHECK: call contract <16 x float> @llvm.amdgcn.mfma.f32.16x16x1f32(float %a, float %b, <16 x float> %c, i32 0, i32 0, i32 0)
void test_mfma_f32_16x16x1f32(global v16f* out, float a, float b, v16f c)
{
*out = __builtin_amdgcn_mfma_f32_16x16x1f32(a, b, c, 0, 0, 0);
}
// CHECK-LABEL: @test_mfma_f32_4x4x1f32
-// CHECK: call <4 x float> @llvm.amdgcn.mfma.f32.4x4x1f32(float %a, float %b, <4 x float> %c, i32 0, i32 0, i32 0)
+// CHECK: call contract <4 x float> @llvm.amdgcn.mfma.f32.4x4x1f32(float %a, float %b, <4 x float> %c, i32 0, i32 0, i32 0)
void test_mfma_f32_4x4x1f32(global v4f* out, float a, float b, v4f c)
{
*out = __builtin_amdgcn_mfma_f32_4x4x1f32(a, b, c, 0, 0, 0);
}
// CHECK-LABEL: @test_mfma_f32_32x32x2f32
-// CHECK: call <16 x float> @llvm.amdgcn.mfma.f32.32x32x2f32(float %a, float %b, <16 x float> %c, i32 0, i32 0, i32 0)
+// CHECK: call contract <16 x float> @llvm.amdgcn.mfma.f32.32x32x2f32(float %a, float %b, <16 x float> %c, i32 0, i32 0, i32 0)
void test_mfma_f32_32x32x2f32(global v16f* out, float a, float b, v16f c)
{
*out = __builtin_amdgcn_mfma_f32_32x32x2f32(a, b, c, 0, 0, 0);
}
// CHECK-LABEL: @test_mfma_f32_16x16x4f32
-// CHECK: call <4 x float> @llvm.amdgcn.mfma.f32.16x16x4f32(float %a, float %b, <4 x float> %c, i32 0, i32 0, i32 0)
+// CHECK: call contract <4 x float> @llvm.amdgcn.mfma.f32.16x16x4f32(float %a, float %b, <4 x float> %c, i32 0, i32 0, i32 0)
void test_mfma_f32_16x16x4f32(global v4f* out, float a, float b, v4f c)
{
*out = __builtin_amdgcn_mfma_f32_16x16x4f32(a, b, c, 0, 0, 0);
}
// CHECK-LABEL: @test_mfma_f32_32x32x4f16
-// CHECK: call <32 x float> @llvm.amdgcn.mfma.f32.32x32x4f16(<4 x half> %a, <4 x half> %b, <32 x float> %c, i32 0, i32 0, i32 0)
+// CHECK: call contract <32 x float> @llvm.amdgcn.mfma.f32.32x32x4f16(<4 x half> %a, <4 x half> %b, <32 x float> %c, i32 0, i32 0, i32 0)
void test_mfma_f32_32x32x4f16(global v32f* out, v4h a, v4h b, v32f c)
{
*out = __builtin_amdgcn_mfma_f32_32x32x4f16(a, b, c, 0, 0, 0);
}
// CHECK-LABEL: @test_mfma_f32_16x16x4f16
-// CHECK: call <16 x float> @llvm.amdgcn.mfma.f32.16x16x4f16(<4 x half> %a, <4 x half> %b, <16 x float> %c, i32 0, i32 0, i32 0)
+// CHECK: call contract <16 x float> @llvm.amdgcn.mfma.f32.16x16x4f16(<4 x half> %a, <4 x half> %b, <16 x float> %c, i32 0, i32 0, i32 0)
void test_mfma_f32_16x16x4f16(global v16f* out, v4h a, v4h b, v16f c)
{
*out = __builtin_amdgcn_mfma_f32_16x16x4f16(a, b, c, 0, 0, 0);
}
// CHECK-LABEL: @test_mfma_f32_4x4x4f16
-// CHECK: call <4 x float> @llvm.amdgcn.mfma.f32.4x4x4f16(<4 x half> %a, <4 x half> %b, <4 x float> %c, i32 0, i32 0, i32 0)
+// CHECK: call contract <4 x float> @llvm.amdgcn.mfma.f32.4x4x4f16(<4 x half> %a, <4 x half> %b, <4 x float> %c, i32 0, i32 0, i32 0)
void test_mfma_f32_4x4x4f16(global v4f* out, v4h a, v4h b, v4f c)
{
*out = __builtin_amdgcn_mfma_f32_4x4x4f16(a, b, c, 0, 0, 0);
}
// CHECK-LABEL: @test_mfma_f32_32x32x8f16
-// CHECK: call <16 x float> @llvm.amdgcn.mfma.f32.32x32x8f16(<4 x half> %a, <4 x half> %b, <16 x float> %c, i32 0, i32 0, i32 0)
+// CHECK: call contract <16 x float> @llvm.amdgcn.mfma.f32.32x32x8f16(<4 x half> %a, <4 x half> %b, <16 x float> %c, i32 0, i32 0, i32 0)
void test_mfma_f32_32x32x8f16(global v16f* out, v4h a, v4h b, v16f c)
{
*out = __builtin_amdgcn_mfma_f32_32x32x8f16(a, b, c, 0, 0, 0);
}
// CHECK-LABEL: @test_mfma_f32_16x16x16f16
-// CHECK: call <4 x float> @llvm.amdgcn.mfma.f32.16x16x16f16(<4 x half> %a, <4 x half> %b, <4 x float> %c, i32 0, i32 0, i32 0)
+// CHECK: call contract <4 x float> @llvm.amdgcn.mfma.f32.16x16x16f16(<4 x half> %a, <4 x half> %b, <4 x float> %c, i32 0, i32 0, i32 0)
void test_mfma_f32_16x16x16f16(global v4f* out, v4h a, v4h b, v4f c)
{
*out = __builtin_amdgcn_mfma_f32_16x16x16f16(a, b, c, 0, 0, 0);
@@ -125,35 +125,35 @@
}
// CHECK-LABEL: @test_mfma_f32_32x32x2bf16
-// CHECK: call <32 x float> @llvm.amdgcn.mfma.f32.32x32x2bf16(<2 x i16> %a, <2 x i16> %b, <32 x float> %c, i32 0, i32 0, i32 0)
+// CHECK: call contract <32 x float> @llvm.amdgcn.mfma.f32.32x32x2bf16(<2 x i16> %a, <2 x i16> %b, <32 x float> %c, i32 0, i32 0, i32 0)
void test_mfma_f32_32x32x2bf16(global v32f* out, v2s a, v2s b, v32f c)
{
*out = __builtin_amdgcn_mfma_f32_32x32x2bf16(a, b, c, 0, 0, 0);
}
// CHECK-LABEL: @test_mfma_f32_16x16x2bf16
-// CHECK: call <16 x float> @llvm.amdgcn.mfma.f32.16x16x2bf16(<2 x i16> %a, <2 x i16> %b, <16 x float> %c, i32 0, i32 0, i32 0)
+// CHECK: call contract <16 x float> @llvm.amdgcn.mfma.f32.16x16x2bf16(<2 x i16> %a, <2 x i16> %b, <16 x float> %c, i32 0, i32 0, i32 0)
void test_mfma_f32_16x16x2bf16(global v16f* out, v2s a, v2s b, v16f c)
{
*out = __builtin_amdgcn_mfma_f32_16x16x2bf16(a, b, c, 0, 0, 0);
}
// CHECK-LABEL: @test_mfma_f32_4x4x2bf16
-// CHECK: call <4 x float> @llvm.amdgcn.mfma.f32.4x4x2bf16(<2 x i16> %a, <2 x i16> %b, <4 x float> %c, i32 0, i32 0, i32 0)
+// CHECK: call contract <4 x float> @llvm.amdgcn.mfma.f32.4x4x2bf16(<2 x i16> %a, <2 x i16> %b, <4 x float> %c, i32 0, i32 0, i32 0)
void test_mfma_f32_4x4x2bf16(global v4f* out, v2s a, v2s b, v4f c)
{
*out = __builtin_amdgcn_mfma_f32_4x4x2bf16(a, b, c, 0, 0, 0);
}
// CHECK-LABEL: @test_mfma_f32_32x32x4bf16
-// CHECK: call <16 x float> @llvm.amdgcn.mfma.f32.32x32x4bf16(<2 x i16> %a, <2 x i16> %b, <16 x float> %c, i32 0, i32 0, i32 0)
+// CHECK: call contract <16 x float> @llvm.amdgcn.mfma.f32.32x32x4bf16(<2 x i16> %a, <2 x i16> %b, <16 x float> %c, i32 0, i32 0, i32 0)
void test_mfma_f32_32x32x4bf16(global v16f* out, v2s a, v2s b, v16f c)
{
*out = __builtin_amdgcn_mfma_f32_32x32x4bf16(a, b, c, 0, 0, 0);
}
// CHECK-LABEL: @test_mfma_f32_16x16x8bf16
-// CHECK: call <4 x float> @llvm.amdgcn.mfma.f32.16x16x8bf16(<2 x i16> %a, <2 x i16> %b, <4 x float> %c, i32 0, i32 0, i32 0)
+// CHECK: call contract <4 x float> @llvm.amdgcn.mfma.f32.16x16x8bf16(<2 x i16> %a, <2 x i16> %b, <4 x float> %c, i32 0, i32 0, i32 0)
void test_mfma_f32_16x16x8bf16(global v4f* out, v2s a, v2s b, v4f c)
{
*out = __builtin_amdgcn_mfma_f32_16x16x8bf16(a, b, c, 0, 0, 0);
Index: clang/test/CodeGenOpenCL/builtins-amdgcn-interp.cl
===================================================================
--- clang/test/CodeGenOpenCL/builtins-amdgcn-interp.cl
+++ clang/test/CodeGenOpenCL/builtins-amdgcn-interp.cl
@@ -19,7 +19,7 @@
// CHECK-LABEL: test_interp_f32
// CHECK: call float @llvm.amdgcn.interp.p1
-// CHECK: call float @llvm.amdgcn.interp.p2
+// CHECK: call contract float @llvm.amdgcn.interp.p2
void test_interp_f32(global float* out, float i, float j, int m0)
{
float p1 = __builtin_amdgcn_interp_p1(i, 1, 4, m0);
@@ -27,7 +27,7 @@
}
// CHECK-LABEL: test_interp_mov
-// CHECK: call float @llvm.amdgcn.interp.mov
+// CHECK: call contract float @llvm.amdgcn.interp.mov
void test_interp_mov(global float* out, float i, float j, int m0)
{
*out = __builtin_amdgcn_interp_mov(2, 3, 4, m0);
Index: clang/test/CodeGenOpenCL/builtins-amdgcn-gfx9.cl
===================================================================
--- clang/test/CodeGenOpenCL/builtins-amdgcn-gfx9.cl
+++ clang/test/CodeGenOpenCL/builtins-amdgcn-gfx9.cl
@@ -5,7 +5,7 @@
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
// CHECK-LABEL: @test_fmed3_f16
-// CHECK: call half @llvm.amdgcn.fmed3.f16(half %a, half %b, half %c)
+// CHECK: call contract half @llvm.amdgcn.fmed3.f16(half %a, half %b, half %c)
void test_fmed3_f16(global half* out, half a, half b, half c)
{
*out = __builtin_amdgcn_fmed3h(a, b, c);
Index: clang/test/CodeGenOpenCL/builtins-amdgcn-dl-insts.cl
===================================================================
--- clang/test/CodeGenOpenCL/builtins-amdgcn-dl-insts.cl
+++ clang/test/CodeGenOpenCL/builtins-amdgcn-dl-insts.cl
@@ -10,8 +10,8 @@
typedef unsigned short __attribute__((ext_vector_type(2))) ushort2;
// CHECK-LABEL: @builtins_amdgcn_dl_insts
-// CHECK: call float @llvm.amdgcn.fdot2(<2 x half> %v2hA, <2 x half> %v2hB, float %fC, i1 false)
-// CHECK: call float @llvm.amdgcn.fdot2(<2 x half> %v2hA, <2 x half> %v2hB, float %fC, i1 true)
+// CHECK: call contract float @llvm.amdgcn.fdot2(<2 x half> %v2hA, <2 x half> %v2hB, float %fC, i1 false)
+// CHECK: call contract float @llvm.amdgcn.fdot2(<2 x half> %v2hA, <2 x half> %v2hB, float %fC, i1 true)
// CHECK: call i32 @llvm.amdgcn.sdot2(<2 x i16> %v2ssA, <2 x i16> %v2ssB, i32 %siC, i1 false)
// CHECK: call i32 @llvm.amdgcn.sdot2(<2 x i16> %v2ssA, <2 x i16> %v2ssB, i32 %siC, i1 true)
Index: clang/test/CodeGen/fpconstrained.cpp
===================================================================
--- clang/test/CodeGen/fpconstrained.cpp
+++ clang/test/CodeGen/fpconstrained.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -x c++ -ftrapping-math -fexceptions -fcxx-exceptions -frounding-math -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=FPMODELSTRICT
// RUN: %clang_cc1 -x c++ -ffp-contract=fast -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s -check-prefix=PRECISE
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
-// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
+// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s -check-prefix=FASTNOCONTRACT
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -ffp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s -check-prefix=MAYTRAP
@@ -27,6 +27,7 @@
// STRICTNOEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
// PRECISE: fadd contract float %{{.*}}, %{{.*}}
// FAST: fadd fast
+ // FASTNOCONTRACT: fadd reassoc nnan ninf nsz arcp afn float
f0 = f1 + f2;
// CHECK: ret void
Index: clang/test/CodeGen/fpconstrained.c
===================================================================
--- clang/test/CodeGen/fpconstrained.c
+++ clang/test/CodeGen/fpconstrained.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -ftrapping-math -frounding-math -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=FPMODELSTRICT
// RUN: %clang_cc1 -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=PRECISE
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
-// RUN: %clang_cc1 -ffast-math -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
+// RUN: %clang_cc1 -ffast-math -emit-llvm -o - %s | FileCheck %s -check-prefix=FASTNOCONTRACT
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s -check-prefix=MAYTRAP
@@ -17,6 +17,7 @@
// STRICTNOEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
// PRECISE: fadd contract float %{{.*}}, %{{.*}}
// FAST: fadd fast
+ // FASTNOCONTRACT: fadd reassoc nnan ninf nsz arcp afn float
f0 = f1 + f2;
// CHECK: ret
Index: clang/test/CodeGen/fp-floatcontrol-stack.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/fp-floatcontrol-stack.cpp
@@ -0,0 +1,257 @@
+// RUN: %clang -c -DDEFAULT=1 -Xclang -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DDEFAULT %s
+// RUN: %clang -c -DEBSTRICT=1 -ffp-exception-behavior=strict -Xclang -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DEBSTRICT %s
+// RUN: %clang -c -DFAST=1 -ffast-math -Xclang -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-FAST %s
+// RUN: %clang -c -DNOHONOR=1 -fno-honor-nans -fno-honor-infinities -Xclang -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-NOHONOR %s
+// XFAIL:*
+
+#define FUN(n) (float z) { return n * z + n; }
+
+float fun_default FUN(1)
+//CHECK-LABEL: define {{.*}} @_Z11fun_defaultf{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: call contract float @llvm.fmuladd{{.*}}
+#endif
+#if EBSTRICT
+// Note that backend wants constrained intrinsics used
+// throughout the function if they are needed anywhere in the function.
+// In that case, operations are built with constrained intrinsics operator
+// but using default settings for exception behavior and rounding mode.
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict
+#endif
+#if FAST
+//CHECK-FAST: fmul fast float
+//CHECK-FAST: fadd fast float
+#endif
+// class ResetScope;
+
+#pragma float_control(except, on, push)
+float exc_on FUN(2)
+//CHECK-LABEL: define {{.*}} @_Z6exc_onf{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: llvm.experimental.constrained.fmul{{.*}}
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmuladd{{.*}}tonearest{{.*}}strict
+#endif
+#if NOHONOR
+//CHECK-NOHONOR: nnan ninf contract float {{.*}}llvm.experimental.constrained.fmuladd{{.*}}tonearest{{.*}}strict
+#endif
+#if FAST
+//CHECK-FAST: fast float {{.*}}llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict
+//CHECK-FAST: fast float {{.*}}llvm.experimental.constrained.fadd{{.*}}tonearest{{.*}}strict
+#endif
+
+// class ResetScope;
+#pragma float_control(pop)
+float exc_pop FUN(5)
+//CHECK-LABEL: define {{.*}} @_Z7exc_popf{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: call contract float @llvm.fmuladd{{.*}}
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmuladd{{.*}}tonearest{{.*}}strict
+#endif
+#if NOHONOR
+//CHECK-NOHONOR: call nnan ninf contract float @llvm.fmuladd{{.*}}
+#endif
+#if FAST
+//CHECK-FAST: fmul fast float
+//CHECK-FAST: fadd fast float
+#endif
+
+// class ResetScope;
+#pragma float_control(except, off)
+float exc_off FUN(5)
+//CHECK-LABEL: define {{.*}} @_Z7exc_offf{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: call contract float @llvm.fmuladd{{.*}}
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: call contract float @llvm.fmuladd{{.*}}
+#endif
+#if NOHONOR
+//CHECK-NOHONOR: call nnan ninf contract float @llvm.fmuladd{{.*}}
+#endif
+#if FAST
+//CHECK-FAST: fmul fast float
+//CHECK-FAST: fadd fast float
+#endif
+
+// class ResetScope;
+#pragma float_control(precise, on, push)
+float precise_on FUN(3)
+//CHECK-LABEL: define {{.*}} @_Z10precise_onf{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: contract float {{.*}}llvm.fmuladd{{.*}}
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: contract float {{.*}}llvm.fmuladd{{.*}}
+#endif
+#if NOHONOR
+// If precise is pushed then all fast-math should be off!
+//CHECK-NOHONOR: call contract float {{.*}}llvm.fmuladd{{.*}}
+#endif
+#if FAST
+//CHECK-FAST: contract float {{.*}}llvm.fmuladd{{.*}}
+#endif
+
+// class ResetScope;
+#pragma float_control(pop)
+float precise_pop FUN(3)
+//CHECK-LABEL: define {{.*}} @_Z11precise_popf{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: contract float {{.*}}llvm.fmuladd{{.*}}
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: contract float {{.*}}llvm.fmuladd{{.*}}
+#endif
+#if NOHONOR
+//CHECK-NOHONOR: call nnan ninf contract float @llvm.fmuladd{{.*}}
+#endif
+#if FAST
+//CHECK-FAST: fmul fast float
+//CHECK-FAST: fadd fast float
+#endif
+// class ResetScope;
+#pragma float_control(precise, off)
+float precise_off FUN(4)
+//CHECK-LABEL: define {{.*}} @_Z11precise_offf{{.*}}
+#if DEFAULT
+// Note: precise_off enables fp_contract=fast and the instructions
+// generated do not include the contract flag, although it was enabled
+// in IRBuilder.
+//CHECK-DDEFAULT: fmul fast float
+//CHECK-DDEFAULT: fadd fast float
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: fmul fast float
+//CHECK-DEBSTRICT: fadd fast float
+#endif
+#if NOHONOR
+// fast math should be enabled, and contract should be fast
+//CHECK-NOHONOR: fmul fast float
+//CHECK-NOHONOR: fadd fast float
+#endif
+#if FAST
+//CHECK-FAST: fmul fast float
+//CHECK-FAST: fadd fast float
+#endif
+
+// class ResetScope;
+#pragma float_control(precise, on)
+float precise_on2 FUN(3)
+//CHECK-LABEL: define {{.*}} @_Z11precise_on2f{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: contract float {{.*}}llvm.fmuladd{{.*}}
+#endif
+#if NOHONOR
+// fast math should be off, and contract should be on
+//CHECK-NOHONOR: contract float {{.*}}llvm.fmuladd{{.*}}
+#endif
+#if FAST
+//CHECK-FAST: contract float {{.*}}llvm.fmuladd{{.*}}
+#endif
+
+// class ResetScope;
+#pragma float_control(push)
+float precise_push FUN(3)
+//CHECK-LABEL: define {{.*}} @_Z12precise_pushf{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: contract float {{.*}}llvm.fmuladd{{.*}}
+#endif
+#if NOHONOR
+//CHECK-NOHONOR: contract float {{.*}}llvm.fmuladd{{.*}}
+#endif
+#if FAST
+//CHECK-FAST: contract float {{.*}}llvm.fmuladd{{.*}}
+#endif
+
+// class ResetScope;
+#pragma float_control(precise, off)
+float precise_off2 FUN(4)
+//CHECK-LABEL: define {{.*}} @_Z12precise_off2f{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: fmul fast float
+//CHECK-DDEFAULT: fadd fast float
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: fmul fast float
+//CHECK-DEBSTRICT: fadd fast float
+#endif
+#if NOHONOR
+// fast math settings since precise is off
+//CHECK-NOHONOR: fmul fast float
+//CHECK-NOHONOR: fadd fast float
+#endif
+#if FAST
+//CHECK-FAST: fmul fast float
+//CHECK-FAST: fadd fast float
+#endif
+
+// class ResetScope;
+#pragma float_control(pop)
+float precise_pop2 FUN(3)
+//CHECK-LABEL: define {{.*}} @_Z12precise_pop2f{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: contract float {{.*}}llvm.fmuladd{{.*}}
+#endif
+#if NOHONOR
+//CHECK-NOHONOR: contract float {{.*}}llvm.fmuladd{{.*}}
+#endif
+#if FAST
+//CHECK-FAST: contract float {{.*}}llvm.fmuladd{{.*}}
+#endif
+
+// class ResetScope;
+// --------- end of push pop test
+#pragma float_control(except, on)
+float y();
+class ON {
+// Settings for top level class initializer revert to command line
+// source pragma's do not pertain.
+float z = 2 + y() * 7;
+//CHECK-LABEL: define {{.*}} void @_ZN2ONC2Ev{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: call contract float {{.*}}llvm.fmuladd
+#endif
+#if EBSTRICT
+//Currently, same as default [command line options not considered]
+//CHECK-DEBSTRICT: call contract float {{.*}}llvm.fmuladd
+#endif
+#if NOHONOR
+//CHECK-NOHONOR: call nnan ninf contract float @llvm.fmuladd{{.*}}
+#endif
+#if FAST
+//CHECK-FAST: fmul fast float
+//CHECK-FAST: fadd fast float
+#endif
+};
+ON on;
+#pragma float_control( except, off)
+class OFF {
+float w = 2 + y() * 7;
+//CHECK-LABEL: define {{.*}} void @_ZN3OFFC2Ev{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: call contract float {{.*}}llvm.fmuladd
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: call contract float {{.*}}llvm.fmuladd
+#endif
+#if NOHONOR
+//CHECK-NOHONOR: call nnan ninf contract float @llvm.fmuladd{{.*}}
+#endif
+#if FAST
+//CHECK-FAST: fmul fast float
+//CHECK-FAST: fadd fast float
+#endif
+};
+OFF off;
Index: clang/test/CodeGen/fp-floatcontrol-pragma.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/fp-floatcontrol-pragma.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+float fff(float x, float y) {
+// CHECK-LABEL: define float @_Z3fffff{{.*}}
+// CHECK: entry
+#pragma float_control(except, on)
+ float z;
+ z = z*z;
+//CHECK: llvm.experimental.constrained.fmul{{.*}}
+ {
+ z = x*y;
+//CHECK: llvm.experimental.constrained.fmul{{.*}}
+ }
+ {
+// This pragma has no effect since if there are any fp intrin in the
+// function then all the operations need to be fp intrin
+#pragma float_control(except, off)
+ z = z + x*y;
+//CHECK: llvm.experimental.constrained.fmul{{.*}}
+ }
+ z = z*z;
+//CHECK: llvm.experimental.constrained.fmul{{.*}}
+ return z;
+}
+float check_precise(float x, float y) {
+// CHECK-LABEL: define float @_Z13check_preciseff{{.*}}
+ float z;
+ {
+#pragma float_control(precise, on)
+ z = x*y + z;
+//CHECK: llvm.fmuladd{{.*}}
+ }
+ {
+#pragma float_control(precise, off)
+ z = x*y + z;
+//CHECK: fmul fast float
+//CHECK: fadd fast float
+ }
+ return z;
+}
+float fma_test1(float a, float b, float c) {
+// CHECK-LABEL define float @_Z9fma_test1fff{{.*}}
+#pragma float_control(precise, on)
+ float x = a * b + c;
+//CHECK: fmuladd
+ return x;
+}
Index: clang/test/CodeGen/fp-floatcontrol-class.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/fp-floatcontrol-class.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang -c -Xclang -emit-llvm -o - %s | FileCheck %s
+// XFAIL:*
+// Verify that float_control does not pertain to initializer expressions
+
+float y();
+float z();
+#pragma float_control(except, on)
+class ON {
+float w = 2 + y() * z();
+// CHECK-LABEL: define {{.*}} void @_ZN2ONC2Ev{{.*}}
+//CHECK: call contract float {{.*}}llvm.fmuladd
+};
+ON on;
+#pragma float_control( except, off)
+class OFF {
+float w = 2 + y() * z();
+// CHECK-LABEL: define {{.*}} void @_ZN3OFFC2Ev{{.*}}
+//CHECK: call contract float {{.*}}llvm.fmuladd
+};
+OFF off;
Index: clang/test/CodeGen/fp-contract-pragma.cpp
===================================================================
--- clang/test/CodeGen/fp-contract-pragma.cpp
+++ clang/test/CodeGen/fp-contract-pragma.cpp
@@ -3,7 +3,7 @@
// Is FP_CONTRACT honored in a simple case?
float fp_contract_1(float a, float b, float c) {
// CHECK: _Z13fp_contract_1fff
-// CHECK: tail call float @llvm.fmuladd
+// CHECK: tail call contract float @llvm.fmuladd
#pragma STDC FP_CONTRACT ON
return a * b + c;
}
@@ -31,7 +31,7 @@
float fp_contract_3(float a, float b, float c) {
// CHECK: _Z13fp_contract_3fff
-// CHECK: tail call float @llvm.fmuladd
+// CHECK: tail call contract float @llvm.fmuladd
return template_muladd<float>(a, b, c);
}
@@ -44,13 +44,13 @@
template class fp_contract_4<int>;
// CHECK: _ZN13fp_contract_4IiE6methodEfff
-// CHECK: tail call float @llvm.fmuladd
+// CHECK: tail call contract float @llvm.fmuladd
// Check file-scoped FP_CONTRACT
#pragma STDC FP_CONTRACT ON
float fp_contract_5(float a, float b, float c) {
// CHECK: _Z13fp_contract_5fff
-// CHECK: tail call float @llvm.fmuladd
+// CHECK: tail call contract float @llvm.fmuladd
return a * b + c;
}
@@ -68,24 +68,24 @@
float fp_contract_7(float a, float b, float c) {
// CHECK: _Z13fp_contract_7fff
-// CHECK: %[[M:.+]] = fmul float %b, 2.000000e+00
-// CHECK-NEXT: fsub float %[[M]], %c
+// CHECK: %[[M:.+]] = fmul contract float %b, 2.000000e+00
+// CHECK-NEXT: fsub contract float %[[M]], %c
#pragma STDC FP_CONTRACT ON
return (a = 2 * b) - c;
}
float fp_contract_8(float a, float b, float c) {
// CHECK: _Z13fp_contract_8fff
-// CHECK: fneg float %c
-// CHECK: tail call float @llvm.fmuladd
+// CHECK: fneg contract float %c
+// CHECK: tail call contract float @llvm.fmuladd
#pragma STDC FP_CONTRACT ON
return a * b - c;
}
float fp_contract_9(float a, float b, float c) {
// CHECK: _Z13fp_contract_9fff
-// CHECK: fneg float %a
-// CHECK: tail call float @llvm.fmuladd
+// CHECK: fneg contract float %a
+// CHECK: tail call contract float @llvm.fmuladd
#pragma STDC FP_CONTRACT ON
return c - a * b;
}
Index: clang/test/CodeGen/fp-contract-on-pragma.cpp
===================================================================
--- clang/test/CodeGen/fp-contract-on-pragma.cpp
+++ clang/test/CodeGen/fp-contract-on-pragma.cpp
@@ -3,7 +3,7 @@
// Is FP_CONTRACT honored in a simple case?
float fp_contract_1(float a, float b, float c) {
// CHECK: _Z13fp_contract_1fff
-// CHECK: tail call float @llvm.fmuladd
+// CHECK: tail call contract float @llvm.fmuladd
#pragma clang fp contract(on)
return a * b + c;
}
@@ -31,7 +31,7 @@
float fp_contract_3(float a, float b, float c) {
// CHECK: _Z13fp_contract_3fff
- // CHECK: tail call float @llvm.fmuladd
+ // CHECK: tail call contract float @llvm.fmuladd
return template_muladd<float>(a, b, c);
}
@@ -45,13 +45,13 @@
template class fp_contract_4<int>;
// CHECK: _ZN13fp_contract_4IiE6methodEfff
-// CHECK: tail call float @llvm.fmuladd
+// CHECK: tail call contract float @llvm.fmuladd
// Check file-scoped FP_CONTRACT
#pragma clang fp contract(on)
float fp_contract_5(float a, float b, float c) {
// CHECK: _Z13fp_contract_5fff
- // CHECK: tail call float @llvm.fmuladd
+ // CHECK: tail call contract float @llvm.fmuladd
return a * b + c;
}
@@ -69,8 +69,8 @@
float fp_contract_7(float a, float b, float c) {
// CHECK: _Z13fp_contract_7fff
-// CHECK: %[[M:.+]] = fmul float %b, 2.000000e+00
-// CHECK-NEXT: fsub float %[[M]], %c
+// CHECK: %[[M:.+]] = fmul contract float %b, 2.000000e+00
+// CHECK-NEXT: fsub contract float %[[M]], %c
#pragma clang fp contract(on)
return (a = 2 * b) - c;
}
Index: clang/test/CodeGen/fast-math.c
===================================================================
--- clang/test/CodeGen/fast-math.c
+++ clang/test/CodeGen/fast-math.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -ffast-math -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s
float f0, f1, f2;
void foo(void) {
Index: clang/test/CodeGen/constrained-math-builtins.c
===================================================================
--- clang/test/CodeGen/constrained-math-builtins.c
+++ clang/test/CodeGen/constrained-math-builtins.c
@@ -154,9 +154,9 @@
(double)f * f - f;
(long double)-f * f + f;
-// CHECK: call float @llvm.experimental.constrained.fmuladd.f32
+// CHECK: call contract float @llvm.experimental.constrained.fmuladd.f32
// CHECK: fneg
-// CHECK: call double @llvm.experimental.constrained.fmuladd.f64
+// CHECK: call contract double @llvm.experimental.constrained.fmuladd.f64
// CHECK: fneg
-// CHECK: call x86_fp80 @llvm.experimental.constrained.fmuladd.f80
+// CHECK: call contract x86_fp80 @llvm.experimental.constrained.fmuladd.f80
};
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -4114,6 +4114,26 @@
Stream.EmitRecord(PACK_PRAGMA_OPTIONS, Record);
}
+/// Write the state of 'pragma float_control' at the end of the module.
+void ASTWriter::WriteFloatControlPragmaOptions(Sema &SemaRef) {
+ // Don't serialize pragma pack state for modules, since it should only take
+ // effect on a per-submodule basis.
+ if (WritingModule)
+ return;
+
+ RecordData Record;
+ Record.push_back(SemaRef.FpPragmaStack.CurrentValue);
+ AddSourceLocation(SemaRef.FpPragmaStack.CurrentPragmaLocation, Record);
+ Record.push_back(SemaRef.FpPragmaStack.Stack.size());
+ for (const auto &StackEntry : SemaRef.FpPragmaStack.Stack) {
+ Record.push_back(StackEntry.Value);
+ AddSourceLocation(StackEntry.PragmaLocation, Record);
+ AddSourceLocation(StackEntry.PragmaPushLocation, Record);
+ AddString(StackEntry.StackSlotLabel, Record);
+ }
+ Stream.EmitRecord(FLOAT_CONTROL_PRAGMA_OPTIONS, Record);
+}
+
void ASTWriter::WriteModuleFileExtension(Sema &SemaRef,
ModuleFileExtensionWriter &Writer) {
// Enter the extension block.
@@ -4832,6 +4852,7 @@
WriteMSPointersToMembersPragmaOptions(SemaRef);
}
WritePackPragmaOptions(SemaRef);
+ WriteFloatControlPragmaOptions(SemaRef);
// Some simple statistics
RecordData::value_type Record[] = {
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -3774,6 +3774,29 @@
}
break;
}
+
+ case FLOAT_CONTROL_PRAGMA_OPTIONS: {
+ if (Record.size() < 3) {
+ Error("invalid pragma pack record");
+ return Failure;
+ }
+ FpPragmaCurrentValue = Record[0];
+ FpPragmaCurrentLocation = ReadSourceLocation(F, Record[1]);
+ unsigned NumStackEntries = Record[2];
+ unsigned Idx = 3;
+ // Reset the stack when importing a new module.
+ FpPragmaStack.clear();
+ for (unsigned I = 0; I < NumStackEntries; ++I) {
+ FpPragmaStackEntry Entry;
+ Entry.Value = Record[Idx++];
+ Entry.Location = ReadSourceLocation(F, Record[Idx++]);
+ Entry.PushLocation = ReadSourceLocation(F, Record[Idx++]);
+ FpPragmaStrings.push_back(ReadString(Record, Idx));
+ Entry.SlotLabel = FpPragmaStrings.back();
+ FpPragmaStack.push_back(Entry);
+ }
+ break;
+ }
}
}
}
@@ -7825,6 +7848,34 @@
SemaObj->PackStack.CurrentPragmaLocation = PragmaPackCurrentLocation;
}
}
+ if (FpPragmaCurrentValue) {
+ // The bottom of the stack might have a default value. It must be adjusted
+ // to the current value to ensure that fp-pragma state is preserved after
+ // popping entries that were included/imported from a PCH/module.
+ bool DropFirst = false;
+ if (!FpPragmaStack.empty() &&
+ FpPragmaStack.front().Location.isInvalid()) {
+ assert(FpPragmaStack.front().Value == SemaObj->FpPragmaStack.DefaultValue
+ && "Expected a default pragma float_control value");
+ SemaObj->FpPragmaStack.Stack.emplace_back(
+ FpPragmaStack.front().SlotLabel, SemaObj->FpPragmaStack.CurrentValue,
+ SemaObj->FpPragmaStack.CurrentPragmaLocation,
+ FpPragmaStack.front().PushLocation);
+ DropFirst = true;
+ }
+ for (const auto &Entry :
+ llvm::makeArrayRef(FpPragmaStack).drop_front(DropFirst ? 1 : 0))
+ SemaObj->FpPragmaStack.Stack.emplace_back(Entry.SlotLabel, Entry.Value,
+ Entry.Location, Entry.PushLocation);
+ if (FpPragmaCurrentLocation.isInvalid()) {
+ assert(*FpPragmaCurrentValue == SemaObj->FpPragmaStack.DefaultValue &&
+ "Expected a default pragma float_control value");
+ // Keep the current values.
+ } else {
+ SemaObj->FpPragmaStack.CurrentValue = *FpPragmaCurrentValue;
+ SemaObj->FpPragmaStack.CurrentPragmaLocation = FpPragmaCurrentLocation;
+ }
+ }
}
IdentifierInfo *ASTReader::get(StringRef Name) {
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -374,6 +374,13 @@
}
void Sema::ActOnStartOfCompoundStmt(bool IsStmtExpr) {
+ if (getFPOptions().isFPConstrained()) {
+ // Mark the current function as usng floating point constrained intrinsics
+ if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext)) {
+ F->setUsesFPIntrin(true);
+ }
+ }
+
PushCompoundScope(IsStmtExpr);
}
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -13130,14 +13130,6 @@
if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid())
return ExprError();
- if (ResultTy->isRealFloatingType() &&
- (getLangOpts().getFPRoundingMode() != LangOptions::FPR_ToNearest ||
- getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore))
- // Mark the current function as usng floating point constrained intrinsics
- if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext)) {
- F->setUsesFPIntrin(true);
- }
-
// Some of the binary operations require promoting operands of half vector to
// float vectors and truncating the result back to half vector. For now, we do
// this only when HalfArgsAndReturn is set (that is, when the target is arm or
Index: clang/lib/Sema/SemaAttr.cpp
===================================================================
--- clang/lib/Sema/SemaAttr.cpp
+++ clang/lib/Sema/SemaAttr.cpp
@@ -407,6 +407,56 @@
Consumer.HandleTopLevelDecl(DeclGroupRef(PDMD));
}
+void Sema::ActOnPragmaFloatControl(SourceLocation Loc,
+ PragmaMsStackAction Action,
+ PragmaFloatControlKind Value) {
+ auto NewValue = FpPragmaStack.CurrentValue;
+ if ((Action == PSK_Push_Set || Action == PSK_Push || Action == PSK_Pop) &&
+ !CurContext->isTranslationUnit()) {
+ // Push and pop can only occur at file scope.
+ Diag(Loc, diag::err_pragma_fc_pp_scope);
+ return;
+ }
+ switch(Value) {
+ default:
+ llvm_unreachable("invalid pragma float_control kind");
+ case PFC_Precise:
+ case PFC_NoPrecise:
+ case PFC_Except:
+ case PFC_NoExcept:
+ switch(Value) {
+ default:
+ llvm_unreachable("invalid pragma float_control kind");
+ case PFC_Precise:
+ FPFeatures.setFPPreciseEnabled(true);
+ break;
+ case PFC_NoPrecise:
+ FPFeatures.setFPPreciseEnabled(false);
+ break;
+ case PFC_Except:
+ FPFeatures.setExceptionMode(LangOptions::FPE_Strict);
+ break;
+ case PFC_NoExcept:
+ FPFeatures.setExceptionMode(LangOptions::FPE_Ignore);
+ break;
+ }
+ NewValue = FPFeatures.getInt();
+ FpPragmaStack.Act(Loc, Action, StringRef(), NewValue);
+ break;
+ case PFC_Push:
+ case PFC_Pop:
+ if (Value == PFC_Pop && FpPragmaStack.Stack.empty())
+ Diag(Loc, diag::warn_pragma_pop_failed) <<
+ "float_control" << "stack empty";
+ FpPragmaStack.Act(Loc, Action, StringRef(), NewValue);
+ if (Value == PFC_Pop) {
+ NewValue = FpPragmaStack.CurrentValue;
+ FPFeatures.Restore(NewValue);
+ }
+ break;
+ }
+}
+
void Sema::ActOnPragmaMSPointersToMembers(
LangOptions::PragmaMSPointersToMembersKind RepresentationMethod,
SourceLocation PragmaLoc) {
Index: clang/lib/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -157,8 +157,9 @@
LangOpts.getMSPointerToMemberRepresentationMethod()),
VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0),
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
- CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
- PragmaAttributeCurrentTargetDecl(nullptr),
+ CodeSegStack(nullptr), FpPragmaStack(FPFeatures.getInt()),
+ CurInitSeg(nullptr),
+ VisContext(nullptr), PragmaAttributeCurrentTargetDecl(nullptr),
IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr),
LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
Index: clang/lib/Parse/Parser.cpp
===================================================================
--- clang/lib/Parse/Parser.cpp
+++ clang/lib/Parse/Parser.cpp
@@ -763,6 +763,9 @@
case tok::annot_pragma_fenv_access:
HandlePragmaFEnvAccess();
return nullptr;
+ case tok::annot_pragma_float_control:
+ HandlePragmaFloatControl();
+ return nullptr;
case tok::annot_pragma_fp:
HandlePragmaFP();
break;
Index: clang/lib/Parse/ParseStmt.cpp
===================================================================
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -353,13 +353,13 @@
case tok::annot_pragma_fp_contract:
ProhibitAttributes(Attrs);
- Diag(Tok, diag::err_pragma_fp_contract_scope);
+ Diag(Tok, diag::err_pragma_file_or_compound_scope) << "fp_contract";
ConsumeAnnotationToken();
return StmtError();
case tok::annot_pragma_fp:
ProhibitAttributes(Attrs);
- Diag(Tok, diag::err_pragma_fp_scope);
+ Diag(Tok, diag::err_pragma_file_or_compound_scope) << "clang fp";
ConsumeAnnotationToken();
return StmtError();
@@ -368,6 +368,12 @@
HandlePragmaFEnvAccess();
return StmtEmpty();
+ case tok::annot_pragma_float_control:
+ ProhibitAttributes(Attrs);
+ Diag(Tok, diag::err_pragma_file_or_compound_scope) << "float_control";
+ ConsumeAnnotationToken();
+ return StmtError();
+
case tok::annot_pragma_opencl_extension:
ProhibitAttributes(Attrs);
HandlePragmaOpenCLExtension();
@@ -936,6 +942,9 @@
case tok::annot_pragma_fenv_access:
HandlePragmaFEnvAccess();
break;
+ case tok::annot_pragma_float_control:
+ HandlePragmaFloatControl();
+ break;
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
break;
Index: clang/lib/Parse/ParsePragma.cpp
===================================================================
--- clang/lib/Parse/ParsePragma.cpp
+++ clang/lib/Parse/ParsePragma.cpp
@@ -184,6 +184,16 @@
Sema &Actions;
};
+struct PragmaFloatControlHandler : public PragmaHandler {
+ PragmaFloatControlHandler(Sema &Actions)
+ : PragmaHandler("float_control"), Actions(Actions) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
+ Token &FirstToken) override;
+
+private:
+ Sema &Actions;
+};
+
struct PragmaMSPointersToMembers : public PragmaHandler {
explicit PragmaMSPointersToMembers() : PragmaHandler("pointers_to_members") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
@@ -334,6 +344,9 @@
PP.AddPragmaHandler(MSCommentHandler.get());
}
+ FloatControlHandler =
+ std::make_unique<PragmaFloatControlHandler>(Actions);
+ PP.AddPragmaHandler(FloatControlHandler.get());
if (getLangOpts().MicrosoftExt) {
MSDetectMismatchHandler =
std::make_unique<PragmaDetectMismatchHandler>(Actions);
@@ -438,6 +451,8 @@
PP.RemovePragmaHandler("clang", PCSectionHandler.get());
PCSectionHandler.reset();
+ PP.RemovePragmaHandler(FloatControlHandler.get());
+ FloatControlHandler.reset();
if (getLangOpts().MicrosoftExt) {
PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
MSDetectMismatchHandler.reset();
@@ -646,6 +661,18 @@
ConsumeAnnotationToken();
}
+void Parser::HandlePragmaFloatControl() {
+ assert(Tok.is(tok::annot_pragma_float_control));
+
+ uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue());
+ Sema::PragmaMsStackAction Action =
+ static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF);
+ PragmaFloatControlKind Kind =
+ PragmaFloatControlKind(Value & 0xFFFF);
+ SourceLocation PragmaLoc = ConsumeAnnotationToken();
+ Actions.ActOnPragmaFloatControl(PragmaLoc, Action, Kind);
+}
+
void Parser::HandlePragmaFEnvAccess() {
assert(Tok.is(tok::annot_pragma_fenv_access));
tok::OnOffSwitch OOS =
@@ -2489,6 +2516,129 @@
PP.EnterToken(AnnotTok, /*IsReinject*/ false);
}
+/// Handle the \#pragma float_control extension.
+///
+/// The syntax is:
+/// \code
+/// #pragma float_control(keyword[, setting] [,push])
+/// \endcode
+/// Where 'keyword' and 'setting' are identifiers.
+// 'keyword' can be: precise, except, push, pop
+// 'setting' can be: on, off
+/// The optional arguments 'setting' and 'push' are supported only
+/// when the keyword is 'precise' or 'except'.
+void PragmaFloatControlHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducer Introducer,
+ Token &Tok) {
+ Sema::PragmaMsStackAction Action = Sema::PSK_Set;
+ SourceLocation FloatControlLoc = Tok.getLocation();
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(FloatControlLoc, diag::err_expected) << tok::l_paren;
+ return;
+ }
+
+ // Read the identifier.
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ }
+
+ // Verify that this is one of the float control options.
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ PragmaFloatControlKind Kind =
+ llvm::StringSwitch<PragmaFloatControlKind>(
+ II->getName())
+ .Case("precise", PFC_Precise)
+ .Case("except", PFC_Except)
+ .Case("push", PFC_Push)
+ .Case("pop", PFC_Pop)
+ .Default(PFC_Unknown);
+ PP.Lex(Tok); // the identifier
+ if (Kind == PFC_Unknown) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_unknown_kind);
+ return;
+ } else if (Kind == PFC_Push ||
+ Kind == PFC_Pop) {
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ }
+ PP.Lex(Tok); // Eat the r_paren
+ Action = (Kind == PFC_Pop) ? Sema::PSK_Pop : Sema::PSK_Push;
+ } else {
+ if (Tok.is(tok::r_paren))
+ // Selecting Precise or Except
+ PP.Lex(Tok); // the r_paren
+ else if (Tok.isNot(tok::comma)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ } else {
+ PP.Lex(Tok); // ,
+ if (!Tok.isAnyIdentifier()) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ }
+ StringRef PushOnOff = Tok.getIdentifierInfo()->getName();
+ if (PushOnOff == "on")
+ // Kind is set correctly
+ ;
+ else if (PushOnOff == "off") {
+ if (Kind == PFC_Precise )
+ Kind = PFC_NoPrecise ;
+ if (Kind == PFC_Except )
+ Kind = PFC_NoExcept ;
+ } else if (PushOnOff == "push") {
+ Action = Sema::PSK_Push_Set;
+ } else {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ }
+ PP.Lex(Tok); // the identifier
+ if (Tok.is(tok::comma)) {
+ PP.Lex(Tok); // ,
+ if (!Tok.isAnyIdentifier()) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ }
+ StringRef ExpectedPush = Tok.getIdentifierInfo()->getName();
+ if (ExpectedPush == "push") {
+ Action = Sema::PSK_Push_Set;
+ } else {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ }
+ PP.Lex(Tok); // the push identifier
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ }
+ PP.Lex(Tok); // the r_paren
+ }
+ }
+ SourceLocation EndLoc = Tok.getLocation();
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "float_control";
+ return;
+ }
+
+ // Note: there is no accomodation for PP callback for this pragma.
+
+ // Enter the annotation.
+ auto TokenArray = std::make_unique<Token[]>(1);
+ TokenArray[0].startToken();
+ TokenArray[0].setKind(tok::annot_pragma_float_control);
+ TokenArray[0].setLocation(FloatControlLoc);
+ TokenArray[0].setAnnotationEndLoc(EndLoc);
+ TokenArray[0].setAnnotationValue(reinterpret_cast<void *>(
+ static_cast<uintptr_t>((Action << 16) | (Kind & 0xFFFF))));
+ PP.EnterTokenStream(std::move(TokenArray), 1,
+ /*DisableMacroExpansion=*/false, /*IsReinject=*/false);
+}
+
/// Handle the Microsoft \#pragma detect_mismatch extension.
///
/// The syntax is:
Index: clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -3361,6 +3361,14 @@
// are complete and we can parse the delayed portions of method
// declarations and the lexed inline method definitions, along with any
// delayed attributes.
+
+ // Save the state of Sema.FPFeatures, and change the setting
+ // to the levels specified on the command line. Previous level
+ // will be restored when the RAII object is destroyed.
+ Sema::FPFeaturesStateRAII SaveFPFeaturesState(Actions);
+ FPOptions fpOptions(getLangOpts());
+ Actions.FPFeatures.Restore(fpOptions.getInt());
+
SourceLocation SavedPrevTokLocation = PrevTokLocation;
ParseLexedPragmas(getCurrentClass());
ParseLexedAttributes(getCurrentClass());
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -2475,6 +2475,7 @@
static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
const TargetOptions &TargetOpts,
PreprocessorOptions &PPOpts,
+ CodeGenOptions &CGOpts,
DiagnosticsEngine &Diags) {
// FIXME: Cleanup per-file based stuff.
LangStandard::Kind LangStd = LangStandard::lang_unspecified;
@@ -3187,6 +3188,15 @@
Opts.UnsafeFPMath = Args.hasArg(OPT_menable_unsafe_fp_math) ||
Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
Args.hasArg(OPT_cl_fast_relaxed_math);
+ Opts.AllowFPReassoc = Opts.FastMath || CGOpts.Reassociate;
+ Opts.NoHonorNaNs = Opts.FastMath || CGOpts.NoNaNsFPMath ||
+ Opts.FiniteMathOnly;
+ Opts.NoHonorInfs = Opts.FastMath || CGOpts.NoInfsFPMath ||
+ Opts.FiniteMathOnly;
+ Opts.NoSignedZero = Opts.FastMath || CGOpts.NoSignedZeros;
+ Opts.AllowRecip = Opts.FastMath || CGOpts.ReciprocalMath;
+ // Currently there's no clang option to enable this individually
+ Opts.ApproxFunc = Opts.FastMath;
if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
StringRef Val = A->getValue();
@@ -3607,7 +3617,7 @@
// Other LangOpts are only initialized when the input is not AST or LLVM IR.
// FIXME: Should we really be calling this for an Language::Asm input?
ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(),
- Res.getPreprocessorOpts(), Diags);
+ Res.getPreprocessorOpts(), Res.getCodeGenOpts(), Diags);
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
LangOpts.ObjCExceptions = 1;
if (T.isOSDarwin() && DashX.isPreprocessed()) {
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -4420,6 +4420,16 @@
}
} // end namespace CodeGen
+
+// Map the LangOption for floating point rounding mode into
+// the corresponding enum in the IR.
+llvm::fp::RoundingMode ToConstrainedRoundingMD(
+ LangOptions::FPRoundingModeKind Kind);
+
+// Map the LangOption for floating point exception behavior into
+// the corresponding enum in the IR.
+llvm::fp::ExceptionBehavior ToConstrainedExceptMD(
+ LangOptions::FPExceptionModeKind Kind);
} // end namespace clang
#endif
Index: clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.cpp
+++ clang/lib/CodeGen/CodeGenFunction.cpp
@@ -117,7 +117,7 @@
// Map the LangOption for rounding mode into
// the corresponding enum in the IR.
-static llvm::fp::RoundingMode ToConstrainedRoundingMD(
+llvm::fp::RoundingMode clang::ToConstrainedRoundingMD(
LangOptions::FPRoundingModeKind Kind) {
switch (Kind) {
@@ -132,7 +132,7 @@
// Map the LangOption for exception behavior into
// the corresponding enum in the IR.
-static llvm::fp::ExceptionBehavior ToConstrainedExceptMD(
+llvm::fp::ExceptionBehavior clang::ToConstrainedExceptMD(
LangOptions::FPExceptionModeKind Kind) {
switch (Kind) {
@@ -149,14 +149,14 @@
auto fpExceptionBehavior = ToConstrainedExceptMD(
getLangOpts().getFPExceptionMode());
+ Builder.setDefaultConstrainedRounding(fpRoundingMode);
+ Builder.setDefaultConstrainedExcept(fpExceptionBehavior);
if (fpExceptionBehavior == llvm::fp::ebIgnore &&
fpRoundingMode == llvm::fp::rmToNearest)
// Constrained intrinsics are not used.
- ;
+ Builder.setIsFPConstrained(false);
else {
Builder.setIsFPConstrained(true);
- Builder.setDefaultConstrainedRounding(fpRoundingMode);
- Builder.setDefaultConstrainedExcept(fpExceptionBehavior);
}
}
@@ -923,9 +923,11 @@
if (FD->isMain())
Fn->addFnAttr(llvm::Attribute::NoRecurse);
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+ Builder.setIsFPConstrained(FD->usesFPIntrin());
if (FD->usesFPIntrin())
Fn->addFnAttr(llvm::Attribute::StrictFP);
+ }
// If a custom alignment is used, force realigning to this alignment on
// any main function which certainly will need it.
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -216,7 +216,14 @@
/// Update the FastMathFlags of LLVM IR from the FPOptions in LangOptions.
static void updateFastMathFlags(llvm::FastMathFlags &FMF,
FPOptions FPFeatures) {
- FMF.setAllowContract(FPFeatures.allowFPContractAcrossStatement());
+ FMF.setAllowReassoc(FPFeatures.allowReassoc());
+ FMF.setNoNaNs(FPFeatures.noNaNs());
+ FMF.setNoInfs(FPFeatures.noInfs());
+ FMF.setNoSignedZeros(FPFeatures.noSignedZeros());
+ FMF.setAllowReciprocal(FPFeatures.allowReciprocal());
+ FMF.setApproxFunc(FPFeatures.approxFunc());
+ FMF.setAllowContract(FPFeatures.allowFPContractAcrossStatement() ||
+ FPFeatures.allowFPContractWithinStatement());
}
/// Propagate fast-math flags from \p Op to the instruction in \p V.
@@ -423,6 +430,36 @@
Value *Visit(Expr *E) {
ApplyDebugLocation DL(CGF, E);
+ if (BinaryOperator * BinOp = dyn_cast<BinaryOperator>(E)) {
+ // Preserve the old values
+ llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
+ auto FPFeatures = BinOp->getFPFeatures();
+ auto NewRoundingBehavior = ToConstrainedRoundingMD(
+ FPFeatures.getRoundingMode());
+ Builder.setDefaultConstrainedRounding(NewRoundingBehavior);
+ auto NewExceptionBehavior = ToConstrainedExceptMD(
+ FPFeatures.getExceptionMode());
+ Builder.setDefaultConstrainedExcept(NewExceptionBehavior);
+ auto FMF = Builder.getFastMathFlags();
+ FMF.setAllowReassoc(FPFeatures.allowReassoc());
+ FMF.setNoNaNs(FPFeatures.noNaNs());
+ FMF.setNoInfs(FPFeatures.noInfs());
+ FMF.setNoSignedZeros(FPFeatures.noSignedZeros());
+ FMF.setAllowReciprocal(FPFeatures.allowReciprocal());
+ FMF.setApproxFunc(FPFeatures.approxFunc());
+ FMF.setAllowContract(FPFeatures.allowFPContractAcrossStatement() ||
+ FPFeatures.allowFPContractWithinStatement());
+ Builder.setFastMathFlags(FMF);
+ assert((CGF.CurFuncDecl==nullptr ||
+ Builder.getIsFPConstrained() ||
+ isa<CXXConstructorDecl>(CGF.CurFuncDecl) ||
+ isa<CXXDestructorDecl>(CGF.CurFuncDecl) ||
+ (NewExceptionBehavior == llvm::fp::ebIgnore &&
+ NewRoundingBehavior == llvm::fp::rmToNearest)) &&
+ "FPConstrained should be enabled on entire function");
+
+ return StmtVisitor<ScalarExprEmitter, Value*>::Visit(E);
+ }
return StmtVisitor<ScalarExprEmitter, Value*>::Visit(E);
}
Index: clang/include/clang/Serialization/ASTWriter.h
===================================================================
--- clang/include/clang/Serialization/ASTWriter.h
+++ clang/include/clang/Serialization/ASTWriter.h
@@ -502,6 +502,7 @@
void WriteMSStructPragmaOptions(Sema &SemaRef);
void WriteMSPointersToMembersPragmaOptions(Sema &SemaRef);
void WritePackPragmaOptions(Sema &SemaRef);
+ void WriteFloatControlPragmaOptions(Sema &SemaRef);
void WriteModuleFileExtension(Sema &SemaRef,
ModuleFileExtensionWriter &Writer);
Index: clang/include/clang/Serialization/ASTReader.h
===================================================================
--- clang/include/clang/Serialization/ASTReader.h
+++ clang/include/clang/Serialization/ASTReader.h
@@ -856,6 +856,18 @@
int PragmaMSPointersToMembersState = -1;
SourceLocation PointersToMembersPragmaLocation;
+ /// The pragma float_control state.
+ Optional<unsigned> FpPragmaCurrentValue;
+ SourceLocation FpPragmaCurrentLocation;
+ struct FpPragmaStackEntry {
+ unsigned Value;
+ SourceLocation Location;
+ SourceLocation PushLocation;
+ StringRef SlotLabel;
+ };
+ llvm::SmallVector<FpPragmaStackEntry, 2> FpPragmaStack;
+ llvm::SmallVector<std::string, 2> FpPragmaStrings;
+
/// The pragma pack state.
Optional<unsigned> PragmaPackCurrentValue;
SourceLocation PragmaPackCurrentLocation;
Index: clang/include/clang/Serialization/ASTBitCodes.h
===================================================================
--- clang/include/clang/Serialization/ASTBitCodes.h
+++ clang/include/clang/Serialization/ASTBitCodes.h
@@ -650,7 +650,10 @@
PP_CONDITIONAL_STACK = 62,
/// A table of skipped ranges within the preprocessing record.
- PPD_SKIPPED_RANGES = 63
+ PPD_SKIPPED_RANGES = 63,
+
+ /// Record code for \#pragma float_control options.
+ FLOAT_CONTROL_PRAGMA_OPTIONS = 64
};
/// Record types used within a source manager block.
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -552,6 +552,9 @@
PragmaStack<StringLiteral *> ConstSegStack;
PragmaStack<StringLiteral *> CodeSegStack;
+ // This stacks the current state of Sema.FPFeatures
+ PragmaStack<unsigned> FpPragmaStack;
+
// RAII object to push / pop sentinel slots for all MS #pragma stacks.
// Actions should be performed only if we enter / exit a C++ method body.
class PragmaStackSentinelRAII {
@@ -9395,6 +9398,11 @@
void ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name,
StringRef Value);
+ /// ActOnPragmaFloatControl - Call on well-formed \#pragma float_control
+ void ActOnPragmaFloatControl(SourceLocation Loc,
+ PragmaMsStackAction Action,
+ PragmaFloatControlKind Value);
+
/// ActOnPragmaUnused - Called on well-formed '\#pragma unused'.
void ActOnPragmaUnused(const Token &Identifier,
Scope *curScope,
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -178,6 +178,7 @@
std::unique_ptr<PragmaHandler> PCSectionHandler;
std::unique_ptr<PragmaHandler> MSCommentHandler;
std::unique_ptr<PragmaHandler> MSDetectMismatchHandler;
+ std::unique_ptr<PragmaHandler> FloatControlHandler;
std::unique_ptr<PragmaHandler> MSPointersToMembers;
std::unique_ptr<PragmaHandler> MSVtorDisp;
std::unique_ptr<PragmaHandler> MSInitSeg;
@@ -721,6 +722,10 @@
/// #pragma STDC FENV_ACCESS...
void HandlePragmaFEnvAccess();
+ /// Handle the annotation token produced for
+ /// #pragma float_control
+ void HandlePragmaFloatControl();
+
/// \brief Handle the annotation token produced for
/// #pragma clang fp ...
void HandlePragmaFP();
Index: clang/include/clang/Basic/TokenKinds.def
===================================================================
--- clang/include/clang/Basic/TokenKinds.def
+++ clang/include/clang/Basic/TokenKinds.def
@@ -806,6 +806,11 @@
// handles them.
PRAGMA_ANNOTATION(pragma_fenv_access)
+// Annotation for #pragma float_control
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+PRAGMA_ANNOTATION(pragma_float_control)
+
// Annotation for #pragma pointers_to_members...
// The lexer produces these so that they only take effect when the parser
// handles them.
Index: clang/include/clang/Basic/PragmaKinds.h
===================================================================
--- clang/include/clang/Basic/PragmaKinds.h
+++ clang/include/clang/Basic/PragmaKinds.h
@@ -25,6 +25,16 @@
PMSST_ON // #pragms ms_struct on
};
+enum PragmaFloatControlKind {
+ PFC_Unknown,
+ PFC_Precise, // #pragma float_control(precise, [,on])
+ PFC_NoPrecise, // #pragma float_control(precise, off)
+ PFC_Except, // #pragma float_control(except [,on])
+ PFC_NoExcept, // #pragma float_control(except, off)
+ PFC_Push, // #pragma float_control(push)
+ PFC_Pop // #pragma float_control(pop)
+};
+
}
#endif
Index: clang/include/clang/Basic/LangOptions.h
===================================================================
--- clang/include/clang/Basic/LangOptions.h
+++ clang/include/clang/Basic/LangOptions.h
@@ -359,25 +359,48 @@
FPOptions() : fp_contract(LangOptions::FPC_Off),
fenv_access(LangOptions::FEA_Off),
rounding(LangOptions::FPR_ToNearest),
- exceptions(LangOptions::FPE_Ignore)
- {}
+ exceptions(LangOptions::FPE_Ignore),
+ allow_reassoc(0),
+ no_nans(0),
+ no_infs(0),
+ no_signed_zeros(0),
+ allow_reciprocal(0),
+ approx_func(0)
+ {}
// Used for serializing.
explicit FPOptions(unsigned I)
: fp_contract(static_cast<LangOptions::FPContractModeKind>(I & 3)),
fenv_access(static_cast<LangOptions::FEnvAccessModeKind>((I >> 2) & 1)),
rounding(static_cast<LangOptions::FPRoundingModeKind>((I >> 3) & 7)),
- exceptions(static_cast<LangOptions::FPExceptionModeKind>((I >> 6) & 3))
+ exceptions(static_cast<LangOptions::FPExceptionModeKind>((I >> 6) & 3)),
+ allow_reassoc((I>>8) & 1),
+ no_nans((I>>9) & 1),
+ no_infs((I>>10) & 1),
+ no_signed_zeros((I>>11) & 1),
+ allow_reciprocal((I>>12) & 1),
+ approx_func((I>>13) & 1)
{}
explicit FPOptions(const LangOptions &LangOpts)
: fp_contract(LangOpts.getDefaultFPContractMode()),
fenv_access(LangOptions::FEA_Off),
- rounding(LangOptions::FPR_ToNearest),
- exceptions(LangOptions::FPE_Ignore)
+ rounding(LangOpts.getFPRoundingMode()),
+ exceptions(LangOpts.getFPExceptionMode()),
+ allow_reassoc(LangOpts.FastMath || LangOpts.AllowFPReassoc),
+ no_nans(LangOpts.FastMath || LangOpts.NoHonorNaNs),
+ no_infs(LangOpts.FastMath || LangOpts.NoHonorInfs),
+ no_signed_zeros(LangOpts.FastMath || LangOpts.NoSignedZero),
+ allow_reciprocal(LangOpts.FastMath || LangOpts.AllowRecip),
+ approx_func(LangOpts.FastMath || LangOpts.ApproxFunc)
{}
// FIXME: Use getDefaultFEnvAccessMode() when available.
+ void setFastMath(bool B = true) {
+ allow_reassoc = no_nans = no_infs = no_signed_zeros = approx_func =
+ allow_reciprocal = B;
+ }
+
bool allowFPContractWithinStatement() const {
return fp_contract == LangOptions::FPC_On;
}
@@ -404,6 +427,18 @@
fenv_access = LangOptions::FEA_On;
}
+ void setFPPreciseEnabled(bool Value) {
+ if (Value) {
+ /* Precise mode implies fp_contract=on and disables ffast-math */
+ setFastMath(false);
+ setAllowFPContractWithinStatement();
+ } else {
+ /* Precise mode implies fp_contract=fast and enables ffast-math */
+ setFastMath(true);
+ setAllowFPContractAcrossStatement();
+ }
+ }
+
void setDisallowFEnvAccess() { fenv_access = LangOptions::FEA_Off; }
LangOptions::FPRoundingModeKind getRoundingMode() const {
@@ -422,6 +457,34 @@
exceptions = EM;
}
+ /// Flag queries
+ bool allowReassoc() const { return allow_reassoc; }
+ bool noNaNs() const { return no_nans; }
+ bool noInfs() const { return no_infs; }
+ bool noSignedZeros() const { return no_signed_zeros; }
+ bool allowReciprocal() const { return allow_reciprocal; }
+ bool approxFunc() const { return approx_func; }
+
+ /// Flag setters
+ void setAllowReassoc(bool B = true) {
+ allow_reassoc = B;
+ }
+ void setNoNaNs(bool B = true) {
+ no_nans = B;
+ }
+ void setNoInfs(bool B = true) {
+ no_infs = B;
+ }
+ void setNoSignedZeros(bool B = true) {
+ no_signed_zeros = B;
+ }
+ void setAllowReciprocal(bool B = true) {
+ allow_reciprocal = B;
+ }
+ void setApproxFunc(bool B = true) {
+ approx_func = B;
+ }
+
bool isFPConstrained() const {
return getRoundingMode() != LangOptions::FPR_ToNearest ||
getExceptionMode() != LangOptions::FPE_Ignore ||
@@ -431,7 +494,24 @@
/// Used to serialize this.
unsigned getInt() const {
return fp_contract | (fenv_access << 2) | (rounding << 3)
- | (exceptions << 6);
+ | (exceptions << 6)
+ | (allow_reassoc << 8) | (no_nans << 9)
+ | (no_infs << 10) | (no_signed_zeros << 11)
+ | (allow_reciprocal << 12) | (approx_func << 13);
+ }
+
+ /// Used with getInt() to manage the float_control pragma stack.
+ void Restore(unsigned I) {
+ fp_contract = (static_cast<LangOptions::FPContractModeKind>(I & 3));
+ fenv_access = (static_cast<LangOptions::FEnvAccessModeKind>((I >> 2) & 1));
+ rounding = (static_cast<LangOptions::FPRoundingModeKind>((I >> 3) & 7));
+ exceptions = (static_cast<LangOptions::FPExceptionModeKind>((I >> 6) & 3));
+ allow_reassoc = ((I>>8) & 1);
+ no_nans = ((I>>9) & 1);
+ no_infs = ((I>>10) & 1);
+ no_signed_zeros = ((I>>11) & 1);
+ allow_reciprocal = ((I>>12) & 1);
+ approx_func = ((I>>13) & 1);
}
private:
@@ -442,6 +522,12 @@
unsigned fenv_access : 1;
unsigned rounding : 3;
unsigned exceptions : 2;
+ unsigned allow_reassoc : 1;
+ unsigned no_nans : 1;
+ unsigned no_infs : 1;
+ unsigned no_signed_zeros : 1;
+ unsigned allow_reciprocal : 1;
+ unsigned approx_func : 1;
};
/// Describes the kind of translation unit being processed.
Index: clang/include/clang/Basic/LangOptions.def
===================================================================
--- clang/include/clang/Basic/LangOptions.def
+++ clang/include/clang/Basic/LangOptions.def
@@ -188,6 +188,12 @@
COMPATIBLE_LANGOPT(FastMath , 1, 0, "fast FP math optimizations, and __FAST_MATH__ predefined macro")
COMPATIBLE_LANGOPT(FiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined macro")
COMPATIBLE_LANGOPT(UnsafeFPMath , 1, 0, "Unsafe Floating Point Math")
+COMPATIBLE_LANGOPT(AllowFPReassoc , 1, 0, "Permit Floating Point reassociation")
+COMPATIBLE_LANGOPT(NoHonorNaNs , 1, 0, "Permit Floating Point optimization without regard to NaN")
+COMPATIBLE_LANGOPT(NoHonorInfs , 1, 0, "Permit Floating Point optimization without regard to infinities")
+COMPATIBLE_LANGOPT(NoSignedZero , 1, 0, "Permit Floating Point optimization without regard to signed zeros")
+COMPATIBLE_LANGOPT(AllowRecip , 1, 0, "Permit Floating Point reciprocal")
+COMPATIBLE_LANGOPT(ApproxFunc , 1, 0, "Permit Floating Point approximation")
BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars")
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -854,6 +854,8 @@
"specifying both a name and alignment to 'pop' is undefined">;
def warn_pragma_pop_failed : Warning<"#pragma %0(pop, ...) failed: %1">,
InGroup<IgnoredPragmas>;
+def err_pragma_fc_pp_scope : Error<
+ "'#pragma float_control push/pop' can only appear at file scope">;
def warn_cxx_ms_struct :
Warning<"ms_struct may not produce Microsoft-compatible layouts for classes "
"with base classes or virtual functions">,
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1109,9 +1109,9 @@
"'#pragma init_seg' is only supported when targeting a "
"Microsoft environment">,
InGroup<IgnoredPragmas>;
-// - #pragma fp_contract
-def err_pragma_fp_contract_scope : Error<
- "'#pragma fp_contract' can only appear at file scope or at the start of a "
+// - #pragma restricted to file scope or start of compound statement
+def err_pragma_file_or_compound_scope : Error<
+ "'#pragma %0' can only appear at file scope or at the start of a "
"compound statement">;
// - #pragma stdc unknown
def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
@@ -1130,6 +1130,12 @@
def err_pragma_detect_mismatch_malformed : Error<
"pragma detect_mismatch is malformed; it requires two comma-separated "
"string literals">;
+// - #pragma float_control
+def err_pragma_float_control_malformed : Error<
+ "pragma float_control is malformed; use 'float_control({push|pop})' or "
+ "'float_control({precise|except}, {on|off} [,push])'">;
+def err_pragma_float_control_unknown_kind : Error<
+ "unknown kind of pragma float_control">;
// - #pragma pointers_to_members
def err_pragma_pointers_to_members_unknown_kind : Error<
"unexpected %0, expected to see one of %select{|'best_case', 'full_generality', }1"
@@ -1297,9 +1303,6 @@
def err_pragma_fp_invalid_argument : Error<
"unexpected argument '%0' to '#pragma clang fp %1'; "
"expected 'on', 'fast' or 'off'">;
-def err_pragma_fp_scope : Error<
- "'#pragma clang fp' can only appear at file scope or at the start of a "
- "compound statement">;
def err_pragma_invalid_keyword : Error<
"invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">;
Index: clang/include/clang/AST/Stmt.h
===================================================================
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -533,7 +533,7 @@
/// This is only meaningful for operations on floating point
/// types and 0 otherwise.
- unsigned FPFeatures : 8;
+ unsigned FPFeatures : 14;
SourceLocation OpLoc;
};
@@ -604,7 +604,7 @@
unsigned OperatorKind : 6;
// Only meaningful for floating point types.
- unsigned FPFeatures : 8;
+ unsigned FPFeatures : 14;
};
class CXXRewrittenBinaryOperatorBitfields {
@@ -1100,7 +1100,7 @@
Stmt &operator=(Stmt &&) = delete;
Stmt(StmtClass SC) {
- static_assert(sizeof(*this) <= 8,
+ static_assert(sizeof(*this) <= 16,
"changing bitfields changed sizeof(Stmt)");
static_assert(sizeof(*this) % alignof(void *) == 0,
"Insufficient alignment!");
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -3045,6 +3045,38 @@
section of the code. This can be useful when fast contraction is otherwise
enabled for the translation unit with the ``-ffp-contract=fast`` flag.
+The ``#pragma float_control`` pragma allows precise floating-point
+semantics and floating-point exception behavior to be specified
+for a section of the source code. This pragma can only appear at file scope or
+at the start of a compound statement (excluding comments). When using within a
+compound statement, the pragma is active within the scope of the compound
+statement. This pragma is modeled after a Microsoft pragma with the
+same spelling and syntax. For pragmas specified at file scope, a stack
+is supported so that the pragma float_control settings can be pushed or popped.
+
+When ``float_control(precise, on)`` is enabled, the section of code governed
+by the pragma behaves as though the command-line option ``ffp-model=precise``
+is enabled. That is, fast-math is disabled and fp-contract=on (fused
+multiply add) is enabled.
+
+When ``float_control(except, on)`` is enabled, the section of code governed
+by the pragma behaves as though the command-line
+ ``ffp-exception-behavior=strict`` is enabled, ``float-control(precise, off)``
+selects ``ffp-exception-behavior=ignore``.
+
+The full syntax this pragma supports is
+``float_control(except|precise, on|off [, push])`` and
+``float_control(push|pop)``.
+The ``push`` and ``pop`` forms can only occur at file scope.
+
+.. code-block:: c++
+
+ for(...) {
+ // This block will be compiled with fno-fast-math and ffp-contract=on
+ #pragma float_control(precise, on)
+ a = b[i] * c[i] + e;
+ }
+
Specifying an attribute for multiple declarations (#pragma clang attribute)
===========================================================================
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits