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>