sepavloff updated this revision to Diff 443606.
sepavloff added a comment.

Rebased and addressed reviever's comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D125625/new/

https://reviews.llvm.org/D125625

Files:
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/lib/CodeGen/CGStmt.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/Parse/ParsePragma.cpp
  clang/test/CodeGen/complex-strictfp.c
  clang/test/CodeGen/pragma-fenv_round.c
  clang/test/CodeGen/pragma-fenv_round.cpp
  clang/test/Parser/pragma-fenv_round.c

Index: clang/test/Parser/pragma-fenv_round.c
===================================================================
--- clang/test/Parser/pragma-fenv_round.c
+++ clang/test/Parser/pragma-fenv_round.c
@@ -6,6 +6,5 @@
   if (x)
     return y + 2;
   #pragma STDC FENV_ROUND FE_DOWNWARD // expected-error{{'#pragma STDC FENV_ROUND' can only appear at file scope or at the start of a compound statement}}
-                                      // expected-warning@-1{{pragma STDC FENV_ROUND is not supported}}
   return x + y;
 }
Index: clang/test/CodeGen/pragma-fenv_round.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/pragma-fenv_round.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -S -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+#pragma STDC FENV_ROUND FE_DOWNWARD
+
+float func_01(float x, float y, float z = 1.0f/3.0f) {
+  return x + y + z;
+}
+// CHECK-LABEL: @_Z7func_01fff
+// CHECK: call void @llvm.set.rounding(i32 3)
+// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.downward", metadata !"fpexcept.ignore")
+// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.downward", metadata !"fpexcept.ignore")
+// CHECK: call void @llvm.set.rounding(i32 1)
+
+float func_02() {
+#pragma STDC FENV_ROUND FE_UPWARD
+  return func_01(1.0f, 2.0f);
+}
+// CHECK-LABEL: @_Z7func_02v
+// CHECK: call void @llvm.set.rounding(i32 2)
+// CHECK: call float @llvm.experimental.constrained.fdiv.f32(float 1.000000e+00, float 3.000000e+00, metadata !"round.downward", metadata !"fpexcept.ignore")
+// CHECK: call noundef float @_Z7func_01fff(float noundef 1.000000e+00, float noundef 2.000000e+00, float noundef {{.*}})
+// CHECK: call void @llvm.set.rounding(i32 1)
+
+float func_03(float x, float y, float z = 1.0f/3.0f) {
+#pragma STDC FENV_ROUND FE_TOWARDZERO
+  return x + y + z;
+}
+// CHECK-LABEL: @_Z7func_03fff
+// CHECK: call void @llvm.set.rounding(i32 0)
+// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK: call void @llvm.set.rounding(i32 1)
+
+float func_04() {
+#pragma STDC FENV_ROUND FE_UPWARD
+  return func_01(1.0f, 2.0f);
+}
+// CHECK-LABEL: @_Z7func_04v
+// CHECK: call void @llvm.set.rounding(i32 2)
+// CHECK: call float @llvm.experimental.constrained.fdiv.f32(float 1.000000e+00, float 3.000000e+00, metadata !"round.downward", metadata !"fpexcept.ignore")
+// CHECK: call noundef float @_Z7func_01fff(float noundef 1.000000e+00, float noundef 2.000000e+00, float noundef {{.*}})
+// CHECK: call void @llvm.set.rounding(i32 1)
Index: clang/test/CodeGen/pragma-fenv_round.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/pragma-fenv_round.c
@@ -0,0 +1,205 @@
+// RUN: %clang_cc1 -S -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+float default_mode = 1.0f / 3.0f;
+// CHECK: @default_mode = global float 0x3FD5555560000000
+
+#pragma STDC FENV_ROUND FE_UPWARD
+float upward = 1.0f / 3.0f;
+// CHECK: @upward = global float 0x3FD5555560000000
+
+#pragma STDC FENV_ROUND FE_DOWNWARD
+float downward = 1.0f / 3.0f;
+// CHECK: @downward = global float 0x3FD5555540000000
+
+#pragma STDC FENV_ROUND FE_DYNAMIC
+float dynamic = 1.0f / 3.0f;
+// CHECK: @dynamic = global float 0x3FD5555560000000
+
+#pragma STDC FENV_ROUND FE_TONEAREST
+
+
+float func_1(float w, float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_TOWARDZERO
+  float result = x * y;
+  {
+    #pragma STDC FENV_ROUND FE_UPWARD
+    result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: @func_1
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 2)
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+
+
+float func_2(float w, float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_TOWARDZERO
+  float result = x * y;
+  {
+    #pragma STDC FENV_ROUND FE_TOWARDZERO
+    result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: @func_2
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+
+
+float func_3(float w, float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_TOWARDZERO
+  float result = x * y;
+  {
+    #pragma STDC FENV_ROUND FE_DYNAMIC
+    result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: @func_3
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+
+
+float func_4(float w, float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_TOWARDZERO
+  float result = x * y;
+  {
+    #pragma STDC FENV_ROUND FE_DYNAMIC
+    #pragma STDC FENV_ACCESS ON
+    result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: @func_4
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+
+
+float func_5(float w, float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_DYNAMIC
+  #pragma STDC FENV_ACCESS ON
+  #pragma clang fp exceptions(ignore)
+  float result = x * y;
+  {
+    #pragma STDC FENV_ROUND FE_UPWARD
+    result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: @func_5
+// CHECK:  call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+// CHECK:  [[RM:%[0-9]+]] = call i32 @llvm.flt.rounds()
+// CHECK:  call void @llvm.set.rounding(i32 2)
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 [[RM]])
+// CHECK:  call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+
+
+float func_6(float w, float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_DYNAMIC
+  #pragma STDC FENV_ACCESS ON
+  #pragma clang fp exceptions(ignore)
+  float result = x * y;
+  {
+    #pragma STDC FENV_ROUND FE_DYNAMIC
+    result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: @func_6
+// CHECK:  call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+// CHECK:  call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+
+
+#pragma STDC FENV_ROUND FE_DOWNWARD
+float func_20(float x, float y) {
+  return x + y;
+}
+
+// CHECK-LABEL: func_20
+// CHECK:  call void @llvm.set.rounding(i32 3)
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.downward", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+
+float func_21(float x, float y) {
+  return x - y;
+}
+
+// CHECK-LABEL: func_21
+// CHECK:  call void @llvm.set.rounding(i32 3)
+// CHECK:  call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.downward", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+
+#pragma STDC FENV_ROUND FE_DOWNWARD
+float func_22(int x) {
+  return x;
+}
+
+// CHECK-LABEL: @func_22
+// CHECK:  call void @llvm.set.rounding(i32 3)
+// CHECK:  call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.downward", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+
+
+#pragma STDC FENV_ROUND FE_DOWNWARD
+float func_23(float w, float x, float y, float z) {
+  #pragma STDC FENV_ROUND FE_TOWARDZERO
+  float result = x * y;
+  {
+    result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: @func_23
+// CHECK:  call void @llvm.set.rounding(i32 0)
+// CHECK:  call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// CHECK:  call void @llvm.set.rounding(i32 1)
+
+float func_24(float w, float x, float y, float z) {
+  #pragma STDC FENV_ACCESS ON
+  #pragma STDC FENV_ROUND FE_DYNAMIC
+  float result = x * y;
+  {
+    #pragma STDC FENV_ROUND FE_TOWARDZERO
+    result += z;
+  }
+  return result - w;
+}
+
+// CHECK-LABEL: func_24
+// CHECK: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// CHECK: [[RM:%.*]] = call i32 @llvm.flt.rounds()
+// CHECK: call void @llvm.set.rounding(i32 0)
+// CHECK: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.strict")
+// CHECK: call void @llvm.set.rounding(i32 [[RM]])
+// CHECK: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// CHECK: call void @llvm.set.rounding(i32 1)
Index: clang/test/CodeGen/complex-strictfp.c
===================================================================
--- clang/test/CodeGen/complex-strictfp.c
+++ clang/test/CodeGen/complex-strictfp.c
@@ -15,16 +15,18 @@
 
 // CHECK-LABEL: @test3a(
 // CHECK-NEXT:  entry:
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 2) #[[ATTR2:[0-9]+]]
 // CHECK-NEXT:    [[TMP0:%.*]] = load double, double* @D, align 8
 // CHECK-NEXT:    [[CF_REAL:%.*]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 0), align 4
 // CHECK-NEXT:    [[CF_IMAG:%.*]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 1), align 4
-// CHECK-NEXT:    [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") #[[ATTR2:[0-9]+]]
+// CHECK-NEXT:    [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") #[[ATTR2]]
 // CHECK-NEXT:    [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") #[[ATTR2]]
 // CHECK-NEXT:    [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[CONV]], double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
 // CHECK-NEXT:    [[CONV2:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[ADD_R]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
 // CHECK-NEXT:    [[CONV3:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[CONV1]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
 // CHECK-NEXT:    store float [[CONV2]], float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 0), align 4
 // CHECK-NEXT:    store float [[CONV3]], float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 1), align 4
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 1) #[[ATTR2]]
 // CHECK-NEXT:    ret void
 //
 void test3a(void) {
@@ -33,6 +35,7 @@
 
 // CHECK-LABEL: @test3b(
 // CHECK-NEXT:  entry:
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 2) #[[ATTR2]]
 // CHECK-NEXT:    [[CF_REAL:%.*]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 0), align 4
 // CHECK-NEXT:    [[CF_IMAG:%.*]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 1), align 4
 // CHECK-NEXT:    [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") #[[ATTR2]]
@@ -40,6 +43,7 @@
 // CHECK-NEXT:    [[TMP0:%.*]] = load double, double* @D, align 8
 // CHECK-NEXT:    [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[TMP0]], double [[CONV]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
 // CHECK-NEXT:    store double [[ADD_R]], double* @D, align 8
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 1) #[[ATTR2]]
 // CHECK-NEXT:    ret void
 //
 void test3b(void) {
@@ -48,6 +52,7 @@
 
 // CHECK-LABEL: @test3c(
 // CHECK-NEXT:  entry:
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 2) #[[ATTR2]]
 // CHECK-NEXT:    [[G1_REAL:%.*]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 0), align 8
 // CHECK-NEXT:    [[G1_IMAG:%.*]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 1), align 8
 // CHECK-NEXT:    [[CF_REAL:%.*]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 0), align 4
@@ -61,6 +66,7 @@
 // CHECK-NEXT:    [[CONV3:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[TMP1]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
 // CHECK-NEXT:    store float [[CONV2]], float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 0), align 4
 // CHECK-NEXT:    store float [[CONV3]], float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 1), align 4
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 1) #[[ATTR2]]
 // CHECK-NEXT:    ret void
 //
 void test3c(void) {
@@ -69,12 +75,14 @@
 
 // CHECK-LABEL: @test3d(
 // CHECK-NEXT:  entry:
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 2) #[[ATTR2]]
 // CHECK-NEXT:    [[G1_REAL:%.*]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 0), align 8
 // CHECK-NEXT:    [[G1_IMAG:%.*]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 1), align 8
 // CHECK-NEXT:    [[TMP0:%.*]] = load double, double* @D, align 8
 // CHECK-NEXT:    [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[G1_REAL]], double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
 // CHECK-NEXT:    store double [[ADD_R]], double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 0), align 8
 // CHECK-NEXT:    store double [[G1_IMAG]], double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 1) #[[ATTR2]]
 // CHECK-NEXT:    ret void
 //
 void test3d(void) {
@@ -83,12 +91,14 @@
 
 // CHECK-LABEL: @test3e(
 // CHECK-NEXT:  entry:
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 2) #[[ATTR2]]
 // CHECK-NEXT:    [[TMP0:%.*]] = load double, double* @D, align 8
 // CHECK-NEXT:    [[G1_REAL:%.*]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 0), align 8
 // CHECK-NEXT:    [[G1_IMAG:%.*]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 1), align 8
 // CHECK-NEXT:    [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[TMP0]], double [[G1_REAL]], metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
 // CHECK-NEXT:    store double [[ADD_R]], double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 0), align 8
 // CHECK-NEXT:    store double [[G1_IMAG]], double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 1), align 8
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 1) #[[ATTR2]]
 // CHECK-NEXT:    ret void
 //
 void test3e(void) {
@@ -97,8 +107,10 @@
 
 // CHECK-LABEL: @t1(
 // CHECK-NEXT:  entry:
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 2) #[[ATTR2]]
 // CHECK-NEXT:    [[CONV:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double 4.000000e+00, metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
 // CHECK-NEXT:    store float [[CONV]], float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 0), align 4
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 1) #[[ATTR2]]
 // CHECK-NEXT:    ret void
 //
 void t1(void) {
@@ -107,8 +119,10 @@
 
 // CHECK-LABEL: @t2(
 // CHECK-NEXT:  entry:
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 2) #[[ATTR2]]
 // CHECK-NEXT:    [[CONV:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double 4.000000e+00, metadata !"round.upward", metadata !"fpexcept.strict") #[[ATTR2]]
 // CHECK-NEXT:    store float [[CONV]], float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 1), align 4
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 1) #[[ATTR2]]
 // CHECK-NEXT:    ret void
 //
 void t2(void) {
@@ -118,6 +132,7 @@
 // CHECK-LABEL: @t91(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[C:%.*]] = alloca [0 x i8], align 1
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 2) #[[ATTR2]]
 // CHECK-NEXT:    br i1 false, label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
 // CHECK:       cond.true:
 // CHECK-NEXT:    [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR2]]
@@ -128,6 +143,7 @@
 // CHECK:       cond.end:
 // CHECK-NEXT:    [[COND_R:%.*]] = phi double [ [[CONV]], [[COND_TRUE]] ], [ [[CONV1]], [[COND_FALSE]] ]
 // CHECK-NEXT:    [[COND_I:%.*]] = phi double [ 0.000000e+00, [[COND_TRUE]] ], [ 0.000000e+00, [[COND_FALSE]] ]
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 1) #[[ATTR2]]
 // CHECK-NEXT:    ret void
 //
 void t91(void) {
@@ -140,6 +156,7 @@
 // CHECK-LABEL: @t92(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[C:%.*]] = alloca [0 x i8], align 1
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 2) #[[ATTR2]]
 // CHECK-NEXT:    br i1 false, label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
 // CHECK:       cond.true:
 // CHECK-NEXT:    [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") #[[ATTR2]]
@@ -150,6 +167,7 @@
 // CHECK:       cond.end:
 // CHECK-NEXT:    [[COND_R:%.*]] = phi double [ [[CONV]], [[COND_TRUE]] ], [ [[CONV1]], [[COND_FALSE]] ]
 // CHECK-NEXT:    [[COND_I:%.*]] = phi double [ 0.000000e+00, [[COND_TRUE]] ], [ 0.000000e+00, [[COND_FALSE]] ]
+// CHECK-NEXT:    call void @llvm.set.rounding(i32 1) #[[ATTR2]]
 // CHECK-NEXT:    ret void
 //
 void t92(void) {
Index: clang/lib/Parse/ParsePragma.cpp
===================================================================
--- clang/lib/Parse/ParsePragma.cpp
+++ clang/lib/Parse/ParsePragma.cpp
@@ -3279,9 +3279,6 @@
     return;
   }
 
-  // Until the pragma is fully implemented, issue a warning.
-  PP.Diag(Tok.getLocation(), diag::warn_stdc_fenv_round_not_supported);
-
   MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1),
                               1);
   Toks[0].startToken();
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -3013,6 +3013,10 @@
   /// Get the record field index as represented in debug info.
   unsigned getDebugInfoFIndex(const RecordDecl *Rec, unsigned FieldIndex);
 
+  /// Optionally emit code that sets required floating-point control modes (like
+  /// rounding direction). Also creates corresponding cleanup action if the code
+  /// is emitted.
+  void emitSetFPControlModes(const CompoundStmt &S);
 
   //===--------------------------------------------------------------------===//
   //                            Declaration Emission
Index: clang/lib/CodeGen/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ clang/lib/CodeGen/CGStmt.cpp
@@ -468,6 +468,43 @@
   return true;
 }
 
+namespace {
+/// Cleanup action that restores floating-point control modes upon leaving
+/// a scope.
+struct FPControlModesCleanup final : EHScopeStack::Cleanup {
+  llvm::Value *PreviousModes;
+  FPControlModesCleanup(llvm::Value *M) : PreviousModes(M) {}
+  void Emit(CodeGenFunction &CGF, Flags flags) override {
+    // TODO: using 'setmode' must be more efficient.
+    CGF.Builder.CreateIntrinsic(llvm::Intrinsic::set_rounding, {},
+                                {PreviousModes});
+  }
+};
+} // namespace
+
+void CodeGenFunction::emitSetFPControlModes(const CompoundStmt &S) {
+  if (!S.hasStoredFPFeatures())
+    return;
+  FPOptionsOverride FPO = S.getStoredFPFeatures();
+  FPOptions FP = FPO.applyOverrides(CurFPFeatures);
+  llvm::RoundingMode OldRM = CurFPFeatures.getRoundingMode();
+  llvm::RoundingMode NewRM = FP.getRoundingMode();
+  if (OldRM == NewRM)
+    return;
+  llvm::Value *PreviousRM = nullptr;
+  if (OldRM == llvm::RoundingMode::Dynamic) {
+    llvm::Function *FGetRound = CGM.getIntrinsic(llvm::Intrinsic::flt_rounds);
+    PreviousRM = Builder.CreateCall(FGetRound);
+  } else {
+    PreviousRM = llvm::ConstantInt::get(Int32Ty, static_cast<uint64_t>(OldRM));
+  }
+  if (NewRM != llvm::RoundingMode::Dynamic)
+    Builder.CreateIntrinsic(
+        llvm::Intrinsic::set_rounding, {},
+        llvm::ConstantInt::get(Int32Ty, static_cast<uint64_t>(NewRM)));
+  EHStack.pushCleanup<FPControlModesCleanup>(NormalAndEHCleanup, PreviousRM);
+}
+
 /// EmitCompoundStmt - Emit a compound statement {..} node.  If GetLast is true,
 /// this captures the expression result of the last sub-statement and returns it
 /// (for use by the statement expression extension).
@@ -491,6 +528,9 @@
   assert((!GetLast || (GetLast && ExprResult)) &&
          "If GetLast is true then the CompoundStmt must have a StmtExprResult");
 
+  // Optionally set up the new FP environment, if the compound statement
+  // contains a pragma that modifies it.
+  emitSetFPControlModes(S);
   CGFPOptionsRAII SavedFPFeatues(*this, S.getNewFPOptions(CurFPFeatures));
 
   Address RetAlloca = Address::invalid();
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1188,9 +1188,6 @@
 // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either
 // outside external declarations or preceding all explicit declarations and
 // statements inside a compound statement.
-def warn_stdc_fenv_round_not_supported :
-   Warning<"pragma STDC FENV_ROUND is not supported">,
-   InGroup<UnknownPragmas>;
 def warn_stdc_unknown_rounding_mode : Warning<
   "invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - ignored">,
   InGroup<IgnoredPragmas>;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D125625: Implementati... Serge Pavlov via Phabricator via cfe-commits

Reply via email to