blob: 748baae0cd6ea429d4117be49fbc073dca4e443e [file] [edit]
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
// On x86_64 __fp16 is a storage-only type: it is stored as a half, but all
// arithmetic is performed by promoting to float and truncating back. Verify
// that ClangIR emits the half storage type directly and routes conversions
// through float (as opposed to the removed llvm.convert.to/from.fp16
// intrinsics).
__fp16 g;
__fp16 gi = 1.5;
// CIR-DAG: cir.global external @g = #cir.fp<0.000000e+00> : !cir.f16
// CIR-DAG: cir.global external @gi = #cir.fp<1.500000e+00> : !cir.f16
// LLVM-DAG: @g = global half 0.000000e+00
// LLVM-DAG: @gi = global half 1.500000e+00
float load_to_float(__fp16 *p) { return *p; }
// CIR-LABEL: cir.func {{.*}}@load_to_float(%arg0: !cir.ptr<!cir.f16> {{.*}}) -> !cir.float
// CIR: %[[VAL:.*]] = cir.load {{.*}} : !cir.ptr<!cir.f16>, !cir.f16
// CIR: %{{.*}} = cir.cast floating %[[VAL]] : !cir.f16 -> !cir.float
// LLVM-LABEL: define {{.*}}float @load_to_float(ptr {{.*}}%{{.*}})
// LLVM: %[[LD:.*]] = load half, ptr %{{.*}}
// LLVM: %{{.*}} = fpext half %[[LD]] to float
void store_from_float(__fp16 *p, float f) { *p = f; }
// CIR-LABEL: cir.func {{.*}}@store_from_float(%arg0: !cir.ptr<!cir.f16> {{.*}}, %arg1: !cir.float {{.*}})
// CIR: %[[F:.*]] = cir.load {{.*}} : !cir.ptr<!cir.float>, !cir.float
// CIR: %[[H:.*]] = cir.cast floating %[[F]] : !cir.float -> !cir.f16
// CIR: cir.store {{.*}} %[[H]], %{{.*}} : !cir.f16, !cir.ptr<!cir.f16>
// LLVM-LABEL: define {{.*}}void @store_from_float(ptr {{.*}}%{{.*}}, float {{.*}}%{{.*}})
// LLVM: %[[TR:.*]] = fptrunc float %{{.*}} to half
// LLVM: store half %[[TR]], ptr %{{.*}}
int half_to_int(__fp16 *p) { return (int)*p; }
// CIR-LABEL: cir.func {{.*}}@half_to_int(%arg0: !cir.ptr<!cir.f16> {{.*}}) -> !s32i
// CIR: %[[VAL:.*]] = cir.load {{.*}} : !cir.ptr<!cir.f16>, !cir.f16
// CIR: %[[FP:.*]] = cir.cast floating %[[VAL]] : !cir.f16 -> !cir.float
// CIR: %{{.*}} = cir.cast float_to_int %[[FP]] : !cir.float -> !s32i
// LLVM-LABEL: define {{.*}}i32 @half_to_int(ptr {{.*}}%{{.*}})
// LLVM: %[[LD:.*]] = load half, ptr %{{.*}}
// LLVM: %[[EXT:.*]] = fpext half %[[LD]] to float
// LLVM: %{{.*}} = fptosi float %[[EXT]] to i32
void add_halves(__fp16 *r, __fp16 *a, __fp16 *b) { *r = *a + *b; }
// CIR-LABEL: cir.func {{.*}}@add_halves(%arg0: !cir.ptr<!cir.f16> {{.*}}, %arg1: !cir.ptr<!cir.f16> {{.*}}, %arg2: !cir.ptr<!cir.f16> {{.*}})
// CIR: %[[A:.*]] = cir.load {{.*}} : !cir.ptr<!cir.f16>, !cir.f16
// CIR: %[[AF:.*]] = cir.cast floating %[[A]] : !cir.f16 -> !cir.float
// CIR: %[[B:.*]] = cir.load {{.*}} : !cir.ptr<!cir.f16>, !cir.f16
// CIR: %[[BF:.*]] = cir.cast floating %[[B]] : !cir.f16 -> !cir.float
// CIR: %[[SUM:.*]] = cir.fadd %[[AF]], %[[BF]] : !cir.float
// CIR: %{{.*}} = cir.cast floating %[[SUM]] : !cir.float -> !cir.f16
// LLVM-LABEL: define {{.*}}void @add_halves(ptr {{.*}}%{{.*}}, ptr {{.*}}%{{.*}}, ptr {{.*}}%{{.*}})
// LLVM: %[[EA:.*]] = fpext half %{{.*}} to float
// LLVM: %[[EB:.*]] = fpext half %{{.*}} to float
// LLVM: %[[ADD:.*]] = fadd float %[[EA]], %[[EB]]
// LLVM: %{{.*}} = fptrunc float %[[ADD]] to half