[clang] [C11] Claim conformance to WG14 N1396 (PR #101214)
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 30 11:03:02 PDT 2024
https://github.com/AaronBallman created https://github.com/llvm/llvm-project/pull/101214
The crux of this paper is that floating point expressions can be evaluated in a wider format, but the return statement in a function should still return a value of the function's return type rather than the wider format type.
Note, this is an Annex F conformance requirement and we do not currently claim conformance to Annex F, so technically we conform either way.
>From 717ec4ad2f6da32484b48492740ef6ed083ca176 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Tue, 30 Jul 2024 14:00:12 -0400
Subject: [PATCH] [C11] Claim conformance to WG14 N1396
The crux of this paper is that floating point expressions can be
evaluated in a wider format, but the return statement in a function
should still return a value of the function's return type rather than
the wider format type.
Note, this is an Annex F conformance requirement and we do not
currently claim conformance to Annex F, so technically we conform
either way.
---
clang/test/C/C11/n1396.c | 140 +++++++++++++++++++++++++++++++++++++++
clang/www/c_status.html | 2 +-
2 files changed, 141 insertions(+), 1 deletion(-)
create mode 100644 clang/test/C/C11/n1396.c
diff --git a/clang/test/C/C11/n1396.c b/clang/test/C/C11/n1396.c
new file mode 100644
index 0000000000000..311b343e2b715
--- /dev/null
+++ b/clang/test/C/C11/n1396.c
@@ -0,0 +1,140 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+/* WG14 N1396: Clang 15
+ * Wide function returns (alternate proposal)
+ *
+ * This only applies if attempting to conform to Annex F. Clang is not claiming
+ * conformance to Annex F, but we do aim for conformance. This means that the
+ * return statement converts the value to the return type of the function
+ * rather than return the result in a wider evaluation format. We test this by
+ * using a return statement without a cast and ensure it produces the same IR
+ * as a return statement with an explicit cast.
+ *
+ * We claim Clang 15 for conformance because that's the first version that
+ * supported #pragma clang fp eval_method source|extended
+ */
+
+// CHECK-LABEL: define dso_local float @extended_float_func(
+// CHECK-SAME: float noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT: store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-NEXT: [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-NEXT: [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-NEXT: ret float [[CONV1]]
+//
+float extended_float_func(float x) {
+#pragma clang fp eval_method(extended)
+ return x * 1.0f;
+}
+
+// CHECK-LABEL: define dso_local float @extended_float_func_cast(
+// CHECK-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT: store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-NEXT: [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-NEXT: [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-NEXT: ret float [[CONV1]]
+//
+float extended_float_func_cast(float x) {
+#pragma clang fp eval_method(extended)
+ return (float)(x * 1.0f);
+}
+
+// CHECK-LABEL: define dso_local float @extended_double_func(
+// CHECK-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT: store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-NEXT: [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-NEXT: [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-NEXT: ret float [[CONV1]]
+//
+float extended_double_func(float x) {
+#pragma clang fp eval_method(extended)
+ return x * 1.0;
+}
+
+// CHECK-LABEL: define dso_local float @extended_double_func_cast(
+// CHECK-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT: store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-NEXT: [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-NEXT: [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-NEXT: ret float [[CONV1]]
+//
+float extended_double_func_cast(float x) {
+#pragma clang fp eval_method(extended)
+ return (float)(x * 1.0);
+}
+
+// CHECK-LABEL: define dso_local float @float_source_func(
+// CHECK-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT: store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP0]], 1.000000e+00
+// CHECK-NEXT: ret float [[MUL]]
+//
+float float_source_func(float x) {
+#pragma clang fp eval_method(source)
+ return x * 1.0f;
+}
+
+// CHECK-LABEL: define dso_local float @float_source_func_cast(
+// CHECK-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT: store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP0]], 1.000000e+00
+// CHECK-NEXT: ret float [[MUL]]
+//
+float float_source_func_cast(float x) {
+#pragma clang fp eval_method(source)
+ return (float)(x * 1.0f);
+}
+
+// CHECK-LABEL: define dso_local float @double_source_func(
+// CHECK-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT: store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-NEXT: [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-NEXT: [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-NEXT: ret float [[CONV1]]
+//
+float double_source_func(float x) {
+#pragma clang fp eval_method(source)
+ return x * 1.0;
+}
+
+// CHECK-LABEL: define dso_local float @double_source_func_cast(
+// CHECK-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT: store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-NEXT: [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-NEXT: [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-NEXT: [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-NEXT: ret float [[CONV1]]
+//
+float double_source_func_cast(float x) {
+#pragma clang fp eval_method(source)
+ return (float)(x * 1.0);
+}
diff --git a/clang/www/c_status.html b/clang/www/c_status.html
index 3ea70b0163c70..025bd08712279 100644
--- a/clang/www/c_status.html
+++ b/clang/www/c_status.html
@@ -501,7 +501,7 @@ <h2 id="c11">C11 implementation status</h2>
<tr>
<td>Wide function returns (alternate proposal)</td>
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1396.htm">N1396</a></td>
- <td class="unknown" align="center">Unknown</td>
+ <td class="full" align="center">Clang 15</td>
</tr>
<tr id="alignment">
<td rowspan="3">Alignment</td>
More information about the cfe-commits
mailing list