Author: Aaron Ballman
Date: 2024-08-02T08:17:40-04:00
New Revision: cb58294f86212aeff45f4a303767fcf4ac7d82ba

URL: 
https://github.com/llvm/llvm-project/commit/cb58294f86212aeff45f4a303767fcf4ac7d82ba
DIFF: 
https://github.com/llvm/llvm-project/commit/cb58294f86212aeff45f4a303767fcf4ac7d82ba.diff

LOG: [C11] Claim conformance to WG14 N1396 (#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.

Added: 
    clang/test/C/C11/n1396.c

Modified: 
    clang/www/c_status.html

Removed: 
    


################################################################################
diff  --git a/clang/test/C/C11/n1396.c b/clang/test/C/C11/n1396.c
new file mode 100644
index 0000000000000..6f76cfe959496
--- /dev/null
+++ b/clang/test/C/C11/n1396.c
@@ -0,0 +1,569 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 5
+// RUN: %clang_cc1 -triple=x86_64 -emit-llvm -o - %s | FileCheck 
--check-prefixes=CHECK-X64 %s
+// RUN: %clang_cc1 -triple=aarch64 -emit-llvm -o - %s | FileCheck 
--check-prefixes=CHECK-AARCH64 %s
+// RUN: %clang_cc1 -triple=arm -emit-llvm -o - %s | FileCheck 
--check-prefixes=CHECK-ARM %s
+// RUN: %clang_cc1 -triple=ppc32 -emit-llvm -o - %s | FileCheck 
--check-prefixes=CHECK-PPC32 %s
+// RUN: %clang_cc1 -triple=ppc64 -emit-llvm -o - %s | FileCheck 
--check-prefixes=CHECK-PPC64 %s
+// RUN: %clang_cc1 -triple=sparcv9 -emit-llvm -o - %s | FileCheck 
--check-prefixes=CHECK-SPARCV9 %s
+
+/* WG14 N1396: Partial
+ * 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.
+ *
+ * Clang conforms on targets other than 32-bit x86 (without SSE2), which is why
+ * support is only partial. Once support for that target is dropped, Clang
+ * should be conforming to this paper on all targets. See
+ * https://github.com/llvm/llvm-project/issues/44218 and other linked issues
+ * for further details.
+ *
+ */
+
+// CHECK-X64-LABEL: define dso_local float @extended_float_func(
+// CHECK-X64-SAME: float noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-X64-NEXT:  [[ENTRY:.*:]]
+// CHECK-X64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-X64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to x86_fp80
+// CHECK-X64-NEXT:    [[MUL:%.*]] = fmul x86_fp80 [[CONV]], 
0xK3FFF8000000000000000
+// CHECK-X64-NEXT:    [[CONV1:%.*]] = fptrunc x86_fp80 [[MUL]] to float
+// CHECK-X64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-AARCH64-LABEL: define dso_local float @extended_float_func(
+// CHECK-AARCH64-SAME: float noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-AARCH64-NEXT:  [[ENTRY:.*:]]
+// CHECK-AARCH64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-AARCH64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to fp128
+// CHECK-AARCH64-NEXT:    [[MUL:%.*]] = fmul fp128 [[CONV]], 
0xL00000000000000003FFF000000000000
+// CHECK-AARCH64-NEXT:    [[CONV1:%.*]] = fptrunc fp128 [[MUL]] to float
+// CHECK-AARCH64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-ARM-LABEL: define dso_local arm_aapcscc float @extended_float_func(
+// CHECK-ARM-SAME: float noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-ARM-NEXT:  [[ENTRY:.*:]]
+// CHECK-ARM-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-ARM-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-ARM-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-ARM-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-ARM-NEXT:    ret float [[CONV1]]
+//
+// CHECK-PPC32-LABEL: define dso_local float @extended_float_func(
+// CHECK-PPC32-SAME: float noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-PPC32-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC32-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC32-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to ppc_fp128
+// CHECK-PPC32-NEXT:    [[MUL:%.*]] = fmul ppc_fp128 [[CONV]], 
0xM3FF00000000000000000000000000000
+// CHECK-PPC32-NEXT:    [[CONV1:%.*]] = fptrunc ppc_fp128 [[MUL]] to float
+// CHECK-PPC32-NEXT:    ret float [[CONV1]]
+//
+// CHECK-PPC64-LABEL: define dso_local float @extended_float_func(
+// CHECK-PPC64-SAME: float noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-PPC64-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to ppc_fp128
+// CHECK-PPC64-NEXT:    [[MUL:%.*]] = fmul ppc_fp128 [[CONV]], 
0xM3FF00000000000000000000000000000
+// CHECK-PPC64-NEXT:    [[CONV1:%.*]] = fptrunc ppc_fp128 [[MUL]] to float
+// CHECK-PPC64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-SPARCV9-LABEL: define dso_local float @extended_float_func(
+// CHECK-SPARCV9-SAME: float noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-SPARCV9-NEXT:  [[ENTRY:.*:]]
+// CHECK-SPARCV9-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-SPARCV9-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to fp128
+// CHECK-SPARCV9-NEXT:    [[MUL:%.*]] = fmul fp128 [[CONV]], 
0xL00000000000000003FFF000000000000
+// CHECK-SPARCV9-NEXT:    [[CONV1:%.*]] = fptrunc fp128 [[MUL]] to float
+// CHECK-SPARCV9-NEXT:    ret float [[CONV1]]
+//
+float extended_float_func(float x) {
+#pragma clang fp eval_method(extended)
+  return x * 1.0f;
+}
+
+// CHECK-X64-LABEL: define dso_local float @extended_float_func_cast(
+// CHECK-X64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-X64-NEXT:  [[ENTRY:.*:]]
+// CHECK-X64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-X64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to x86_fp80
+// CHECK-X64-NEXT:    [[MUL:%.*]] = fmul x86_fp80 [[CONV]], 
0xK3FFF8000000000000000
+// CHECK-X64-NEXT:    [[CONV1:%.*]] = fptrunc x86_fp80 [[MUL]] to float
+// CHECK-X64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-AARCH64-LABEL: define dso_local float @extended_float_func_cast(
+// CHECK-AARCH64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-AARCH64-NEXT:  [[ENTRY:.*:]]
+// CHECK-AARCH64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-AARCH64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to fp128
+// CHECK-AARCH64-NEXT:    [[MUL:%.*]] = fmul fp128 [[CONV]], 
0xL00000000000000003FFF000000000000
+// CHECK-AARCH64-NEXT:    [[CONV1:%.*]] = fptrunc fp128 [[MUL]] to float
+// CHECK-AARCH64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-ARM-LABEL: define dso_local arm_aapcscc float 
@extended_float_func_cast(
+// CHECK-ARM-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-ARM-NEXT:  [[ENTRY:.*:]]
+// CHECK-ARM-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-ARM-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-ARM-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-ARM-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-ARM-NEXT:    ret float [[CONV1]]
+//
+// CHECK-PPC32-LABEL: define dso_local float @extended_float_func_cast(
+// CHECK-PPC32-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-PPC32-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC32-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC32-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to ppc_fp128
+// CHECK-PPC32-NEXT:    [[MUL:%.*]] = fmul ppc_fp128 [[CONV]], 
0xM3FF00000000000000000000000000000
+// CHECK-PPC32-NEXT:    [[CONV1:%.*]] = fptrunc ppc_fp128 [[MUL]] to float
+// CHECK-PPC32-NEXT:    ret float [[CONV1]]
+//
+// CHECK-PPC64-LABEL: define dso_local float @extended_float_func_cast(
+// CHECK-PPC64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-PPC64-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to ppc_fp128
+// CHECK-PPC64-NEXT:    [[MUL:%.*]] = fmul ppc_fp128 [[CONV]], 
0xM3FF00000000000000000000000000000
+// CHECK-PPC64-NEXT:    [[CONV1:%.*]] = fptrunc ppc_fp128 [[MUL]] to float
+// CHECK-PPC64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-SPARCV9-LABEL: define dso_local float @extended_float_func_cast(
+// CHECK-SPARCV9-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-SPARCV9-NEXT:  [[ENTRY:.*:]]
+// CHECK-SPARCV9-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-SPARCV9-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to fp128
+// CHECK-SPARCV9-NEXT:    [[MUL:%.*]] = fmul fp128 [[CONV]], 
0xL00000000000000003FFF000000000000
+// CHECK-SPARCV9-NEXT:    [[CONV1:%.*]] = fptrunc fp128 [[MUL]] to float
+// CHECK-SPARCV9-NEXT:    ret float [[CONV1]]
+//
+float extended_float_func_cast(float x) {
+#pragma clang fp eval_method(extended)
+  return (float)(x * 1.0f);
+}
+
+// CHECK-X64-LABEL: define dso_local float @extended_double_func(
+// CHECK-X64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-X64-NEXT:  [[ENTRY:.*:]]
+// CHECK-X64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-X64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to x86_fp80
+// CHECK-X64-NEXT:    [[MUL:%.*]] = fmul x86_fp80 [[CONV]], 
0xK3FFF8000000000000000
+// CHECK-X64-NEXT:    [[CONV1:%.*]] = fptrunc x86_fp80 [[MUL]] to float
+// CHECK-X64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-AARCH64-LABEL: define dso_local float @extended_double_func(
+// CHECK-AARCH64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-AARCH64-NEXT:  [[ENTRY:.*:]]
+// CHECK-AARCH64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-AARCH64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to fp128
+// CHECK-AARCH64-NEXT:    [[MUL:%.*]] = fmul fp128 [[CONV]], 
0xL00000000000000003FFF000000000000
+// CHECK-AARCH64-NEXT:    [[CONV1:%.*]] = fptrunc fp128 [[MUL]] to float
+// CHECK-AARCH64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-ARM-LABEL: define dso_local arm_aapcscc float @extended_double_func(
+// CHECK-ARM-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-ARM-NEXT:  [[ENTRY:.*:]]
+// CHECK-ARM-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-ARM-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-ARM-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-ARM-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-ARM-NEXT:    ret float [[CONV1]]
+//
+// CHECK-PPC32-LABEL: define dso_local float @extended_double_func(
+// CHECK-PPC32-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-PPC32-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC32-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC32-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to ppc_fp128
+// CHECK-PPC32-NEXT:    [[MUL:%.*]] = fmul ppc_fp128 [[CONV]], 
0xM3FF00000000000000000000000000000
+// CHECK-PPC32-NEXT:    [[CONV1:%.*]] = fptrunc ppc_fp128 [[MUL]] to float
+// CHECK-PPC32-NEXT:    ret float [[CONV1]]
+//
+// CHECK-PPC64-LABEL: define dso_local float @extended_double_func(
+// CHECK-PPC64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-PPC64-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to ppc_fp128
+// CHECK-PPC64-NEXT:    [[MUL:%.*]] = fmul ppc_fp128 [[CONV]], 
0xM3FF00000000000000000000000000000
+// CHECK-PPC64-NEXT:    [[CONV1:%.*]] = fptrunc ppc_fp128 [[MUL]] to float
+// CHECK-PPC64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-SPARCV9-LABEL: define dso_local float @extended_double_func(
+// CHECK-SPARCV9-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-SPARCV9-NEXT:  [[ENTRY:.*:]]
+// CHECK-SPARCV9-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-SPARCV9-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to fp128
+// CHECK-SPARCV9-NEXT:    [[MUL:%.*]] = fmul fp128 [[CONV]], 
0xL00000000000000003FFF000000000000
+// CHECK-SPARCV9-NEXT:    [[CONV1:%.*]] = fptrunc fp128 [[MUL]] to float
+// CHECK-SPARCV9-NEXT:    ret float [[CONV1]]
+//
+float extended_double_func(float x) {
+#pragma clang fp eval_method(extended)
+  return x * 1.0;
+}
+
+// CHECK-X64-LABEL: define dso_local float @extended_double_func_cast(
+// CHECK-X64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-X64-NEXT:  [[ENTRY:.*:]]
+// CHECK-X64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-X64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to x86_fp80
+// CHECK-X64-NEXT:    [[MUL:%.*]] = fmul x86_fp80 [[CONV]], 
0xK3FFF8000000000000000
+// CHECK-X64-NEXT:    [[CONV1:%.*]] = fptrunc x86_fp80 [[MUL]] to float
+// CHECK-X64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-AARCH64-LABEL: define dso_local float @extended_double_func_cast(
+// CHECK-AARCH64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-AARCH64-NEXT:  [[ENTRY:.*:]]
+// CHECK-AARCH64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-AARCH64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to fp128
+// CHECK-AARCH64-NEXT:    [[MUL:%.*]] = fmul fp128 [[CONV]], 
0xL00000000000000003FFF000000000000
+// CHECK-AARCH64-NEXT:    [[CONV1:%.*]] = fptrunc fp128 [[MUL]] to float
+// CHECK-AARCH64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-ARM-LABEL: define dso_local arm_aapcscc float 
@extended_double_func_cast(
+// CHECK-ARM-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-ARM-NEXT:  [[ENTRY:.*:]]
+// CHECK-ARM-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-ARM-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-ARM-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-ARM-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-ARM-NEXT:    ret float [[CONV1]]
+//
+// CHECK-PPC32-LABEL: define dso_local float @extended_double_func_cast(
+// CHECK-PPC32-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-PPC32-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC32-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC32-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to ppc_fp128
+// CHECK-PPC32-NEXT:    [[MUL:%.*]] = fmul ppc_fp128 [[CONV]], 
0xM3FF00000000000000000000000000000
+// CHECK-PPC32-NEXT:    [[CONV1:%.*]] = fptrunc ppc_fp128 [[MUL]] to float
+// CHECK-PPC32-NEXT:    ret float [[CONV1]]
+//
+// CHECK-PPC64-LABEL: define dso_local float @extended_double_func_cast(
+// CHECK-PPC64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-PPC64-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to ppc_fp128
+// CHECK-PPC64-NEXT:    [[MUL:%.*]] = fmul ppc_fp128 [[CONV]], 
0xM3FF00000000000000000000000000000
+// CHECK-PPC64-NEXT:    [[CONV1:%.*]] = fptrunc ppc_fp128 [[MUL]] to float
+// CHECK-PPC64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-SPARCV9-LABEL: define dso_local float @extended_double_func_cast(
+// CHECK-SPARCV9-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-SPARCV9-NEXT:  [[ENTRY:.*:]]
+// CHECK-SPARCV9-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-SPARCV9-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to fp128
+// CHECK-SPARCV9-NEXT:    [[MUL:%.*]] = fmul fp128 [[CONV]], 
0xL00000000000000003FFF000000000000
+// CHECK-SPARCV9-NEXT:    [[CONV1:%.*]] = fptrunc fp128 [[MUL]] to float
+// CHECK-SPARCV9-NEXT:    ret float [[CONV1]]
+//
+float extended_double_func_cast(float x) {
+#pragma clang fp eval_method(extended)
+  return (float)(x * 1.0);
+}
+
+// CHECK-X64-LABEL: define dso_local float @float_source_func(
+// CHECK-X64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-X64-NEXT:  [[ENTRY:.*:]]
+// CHECK-X64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-X64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[MUL:%.*]] = fmul float [[TMP0]], 1.000000e+00
+// CHECK-X64-NEXT:    ret float [[MUL]]
+//
+// CHECK-AARCH64-LABEL: define dso_local float @float_source_func(
+// CHECK-AARCH64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-AARCH64-NEXT:  [[ENTRY:.*:]]
+// CHECK-AARCH64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-AARCH64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[MUL:%.*]] = fmul float [[TMP0]], 1.000000e+00
+// CHECK-AARCH64-NEXT:    ret float [[MUL]]
+//
+// CHECK-ARM-LABEL: define dso_local arm_aapcscc float @float_source_func(
+// CHECK-ARM-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-ARM-NEXT:  [[ENTRY:.*:]]
+// CHECK-ARM-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-ARM-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[MUL:%.*]] = fmul float [[TMP0]], 1.000000e+00
+// CHECK-ARM-NEXT:    ret float [[MUL]]
+//
+// CHECK-PPC32-LABEL: define dso_local float @float_source_func(
+// CHECK-PPC32-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-PPC32-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC32-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC32-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[MUL:%.*]] = fmul float [[TMP0]], 1.000000e+00
+// CHECK-PPC32-NEXT:    ret float [[MUL]]
+//
+// CHECK-PPC64-LABEL: define dso_local float @float_source_func(
+// CHECK-PPC64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-PPC64-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[MUL:%.*]] = fmul float [[TMP0]], 1.000000e+00
+// CHECK-PPC64-NEXT:    ret float [[MUL]]
+//
+// CHECK-SPARCV9-LABEL: define dso_local float @float_source_func(
+// CHECK-SPARCV9-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-SPARCV9-NEXT:  [[ENTRY:.*:]]
+// CHECK-SPARCV9-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-SPARCV9-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[MUL:%.*]] = fmul float [[TMP0]], 1.000000e+00
+// CHECK-SPARCV9-NEXT:    ret float [[MUL]]
+//
+float float_source_func(float x) {
+#pragma clang fp eval_method(source)
+  return x * 1.0f;
+}
+
+// CHECK-X64-LABEL: define dso_local float @float_source_func_cast(
+// CHECK-X64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-X64-NEXT:  [[ENTRY:.*:]]
+// CHECK-X64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-X64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[MUL:%.*]] = fmul float [[TMP0]], 1.000000e+00
+// CHECK-X64-NEXT:    ret float [[MUL]]
+//
+// CHECK-AARCH64-LABEL: define dso_local float @float_source_func_cast(
+// CHECK-AARCH64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-AARCH64-NEXT:  [[ENTRY:.*:]]
+// CHECK-AARCH64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-AARCH64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[MUL:%.*]] = fmul float [[TMP0]], 1.000000e+00
+// CHECK-AARCH64-NEXT:    ret float [[MUL]]
+//
+// CHECK-ARM-LABEL: define dso_local arm_aapcscc float @float_source_func_cast(
+// CHECK-ARM-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-ARM-NEXT:  [[ENTRY:.*:]]
+// CHECK-ARM-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-ARM-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[MUL:%.*]] = fmul float [[TMP0]], 1.000000e+00
+// CHECK-ARM-NEXT:    ret float [[MUL]]
+//
+// CHECK-PPC32-LABEL: define dso_local float @float_source_func_cast(
+// CHECK-PPC32-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-PPC32-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC32-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC32-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[MUL:%.*]] = fmul float [[TMP0]], 1.000000e+00
+// CHECK-PPC32-NEXT:    ret float [[MUL]]
+//
+// CHECK-PPC64-LABEL: define dso_local float @float_source_func_cast(
+// CHECK-PPC64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-PPC64-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[MUL:%.*]] = fmul float [[TMP0]], 1.000000e+00
+// CHECK-PPC64-NEXT:    ret float [[MUL]]
+//
+// CHECK-SPARCV9-LABEL: define dso_local float @float_source_func_cast(
+// CHECK-SPARCV9-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-SPARCV9-NEXT:  [[ENTRY:.*:]]
+// CHECK-SPARCV9-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-SPARCV9-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[MUL:%.*]] = fmul float [[TMP0]], 1.000000e+00
+// CHECK-SPARCV9-NEXT:    ret float [[MUL]]
+//
+float float_source_func_cast(float x) {
+#pragma clang fp eval_method(source)
+  return (float)(x * 1.0f);
+}
+
+// CHECK-X64-LABEL: define dso_local float @double_source_func(
+// CHECK-X64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-X64-NEXT:  [[ENTRY:.*:]]
+// CHECK-X64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-X64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-X64-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-X64-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-X64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-AARCH64-LABEL: define dso_local float @double_source_func(
+// CHECK-AARCH64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-AARCH64-NEXT:  [[ENTRY:.*:]]
+// CHECK-AARCH64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-AARCH64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-AARCH64-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-AARCH64-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-AARCH64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-ARM-LABEL: define dso_local arm_aapcscc float @double_source_func(
+// CHECK-ARM-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-ARM-NEXT:  [[ENTRY:.*:]]
+// CHECK-ARM-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-ARM-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-ARM-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-ARM-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-ARM-NEXT:    ret float [[CONV1]]
+//
+// CHECK-PPC32-LABEL: define dso_local float @double_source_func(
+// CHECK-PPC32-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-PPC32-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC32-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC32-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-PPC32-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-PPC32-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-PPC32-NEXT:    ret float [[CONV1]]
+//
+// CHECK-PPC64-LABEL: define dso_local float @double_source_func(
+// CHECK-PPC64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-PPC64-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-PPC64-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-PPC64-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-PPC64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-SPARCV9-LABEL: define dso_local float @double_source_func(
+// CHECK-SPARCV9-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-SPARCV9-NEXT:  [[ENTRY:.*:]]
+// CHECK-SPARCV9-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-SPARCV9-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-SPARCV9-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-SPARCV9-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-SPARCV9-NEXT:    ret float [[CONV1]]
+//
+float double_source_func(float x) {
+#pragma clang fp eval_method(source)
+  return x * 1.0;
+}
+
+// CHECK-X64-LABEL: define dso_local float @double_source_func_cast(
+// CHECK-X64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-X64-NEXT:  [[ENTRY:.*:]]
+// CHECK-X64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-X64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-X64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-X64-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-X64-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-X64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-AARCH64-LABEL: define dso_local float @double_source_func_cast(
+// CHECK-AARCH64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-AARCH64-NEXT:  [[ENTRY:.*:]]
+// CHECK-AARCH64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-AARCH64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-AARCH64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-AARCH64-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-AARCH64-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-AARCH64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-ARM-LABEL: define dso_local arm_aapcscc float 
@double_source_func_cast(
+// CHECK-ARM-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-ARM-NEXT:  [[ENTRY:.*:]]
+// CHECK-ARM-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-ARM-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-ARM-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-ARM-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-ARM-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-ARM-NEXT:    ret float [[CONV1]]
+//
+// CHECK-PPC32-LABEL: define dso_local float @double_source_func_cast(
+// CHECK-PPC32-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-PPC32-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC32-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC32-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC32-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-PPC32-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-PPC32-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-PPC32-NEXT:    ret float [[CONV1]]
+//
+// CHECK-PPC64-LABEL: define dso_local float @double_source_func_cast(
+// CHECK-PPC64-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-PPC64-NEXT:  [[ENTRY:.*:]]
+// CHECK-PPC64-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-PPC64-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-PPC64-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-PPC64-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-PPC64-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-PPC64-NEXT:    ret float [[CONV1]]
+//
+// CHECK-SPARCV9-LABEL: define dso_local float @double_source_func_cast(
+// CHECK-SPARCV9-SAME: float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-SPARCV9-NEXT:  [[ENTRY:.*:]]
+// CHECK-SPARCV9-NEXT:    [[X_ADDR:%.*]] = alloca float, align 4
+// CHECK-SPARCV9-NEXT:    store float [[X]], ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4
+// CHECK-SPARCV9-NEXT:    [[CONV:%.*]] = fpext float [[TMP0]] to double
+// CHECK-SPARCV9-NEXT:    [[MUL:%.*]] = fmul double [[CONV]], 1.000000e+00
+// CHECK-SPARCV9-NEXT:    [[CONV1:%.*]] = fptrunc double [[MUL]] to float
+// CHECK-SPARCV9-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..0a80039a10578 100644
--- a/clang/www/c_status.html
+++ b/clang/www/c_status.html
@@ -501,7 +501,14 @@ <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">
+        <details><summary>Yes*</summary>
+        Clang conforms to this paper on all targets except 32-bit x86 without
+        SSE2. However, Clang does not claim conformance to Annex F on any
+        target and does not intend to ever conform to Annex F on that specific
+        target, so no changes are needed to conform to this paper.
+        </details>
+      </td>
     </tr>
     <tr id="alignment">
       <td rowspan="3">Alignment</td>


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to