Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[C11] Claim conformance to WG14 N1396 #101214

Merged
merged 5 commits into from
Aug 2, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
569 changes: 569 additions & 0 deletions clang/test/C/C11/n1396.c
Original file line number Diff line number Diff line change
@@ -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);
}
9 changes: 8 additions & 1 deletion clang/www/c_status.html
Original file line number Diff line number Diff line change
@@ -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>