mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 15:26:06 +00:00
[RISCV][BF16] Enable __bf16 for riscv targets
The RISC-V psABI recently added __bf16 in https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/367. Now we can enable this new type in clang. Reviewed By: craig.topper Differential Revision: https://reviews.llvm.org/D150929
This commit is contained in:
parent
93a3706711
commit
a5791bfef4
@ -816,6 +816,7 @@ to ``float``; see below for more information on this emulation.
|
||||
* ``__bf16`` is supported on the following targets (currently never natively):
|
||||
* 32-bit ARM
|
||||
* 64-bit ARM (AArch64)
|
||||
* RISC-V
|
||||
* X86 (when SSE2 is available)
|
||||
|
||||
(For X86, SSE2 is available on 64-bit and all recent 32-bit processors.)
|
||||
|
@ -32,6 +32,9 @@ protected:
|
||||
public:
|
||||
RISCVTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
|
||||
: TargetInfo(Triple) {
|
||||
BFloat16Width = 16;
|
||||
BFloat16Align = 16;
|
||||
BFloat16Format = &llvm::APFloat::BFloat();
|
||||
LongDoubleWidth = 128;
|
||||
LongDoubleAlign = 128;
|
||||
LongDoubleFormat = &llvm::APFloat::IEEEquad();
|
||||
@ -101,6 +104,8 @@ public:
|
||||
|
||||
bool hasBitIntType() const override { return true; }
|
||||
|
||||
bool hasBFloat16Type() const override { return true; }
|
||||
|
||||
bool useFP16ConversionIntrinsics() const override {
|
||||
return false;
|
||||
}
|
||||
|
587
clang/test/CodeGen/RISCV/bfloat-abi.c
Normal file
587
clang/test/CodeGen/RISCV/bfloat-abi.c
Normal file
@ -0,0 +1,587 @@
|
||||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2
|
||||
// RUN: %clang_cc1 -triple riscv64 -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK-RV64
|
||||
// RUN: %clang_cc1 -triple riscv32 -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK-RV32
|
||||
|
||||
struct bfloat1 {
|
||||
__bf16 a;
|
||||
};
|
||||
|
||||
// CHECK-RV64-LABEL: define dso_local i64 @h1
|
||||
// CHECK-RV64-SAME: (bfloat noundef [[A:%.*]]) #[[ATTR0:[0-9]+]] {
|
||||
// CHECK-RV64-NEXT: entry:
|
||||
// CHECK-RV64-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_BFLOAT1:%.*]], align 2
|
||||
// CHECK-RV64-NEXT: [[A_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[COERCE_DIVE_COERCE:%.*]] = alloca i64, align 8
|
||||
// CHECK-RV64-NEXT: store bfloat [[A]], ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT1]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP0]], ptr [[A1]], align 2
|
||||
// CHECK-RV64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT1]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV64-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[COERCE_DIVE_COERCE]], ptr align 2 [[COERCE_DIVE]], i64 2, i1 false)
|
||||
// CHECK-RV64-NEXT: [[TMP1:%.*]] = load i64, ptr [[COERCE_DIVE_COERCE]], align 8
|
||||
// CHECK-RV64-NEXT: ret i64 [[TMP1]]
|
||||
//
|
||||
// CHECK-RV32-LABEL: define dso_local i32 @h1
|
||||
// CHECK-RV32-SAME: (bfloat noundef [[A:%.*]]) #[[ATTR0:[0-9]+]] {
|
||||
// CHECK-RV32-NEXT: entry:
|
||||
// CHECK-RV32-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_BFLOAT1:%.*]], align 2
|
||||
// CHECK-RV32-NEXT: [[A_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[COERCE_DIVE_COERCE:%.*]] = alloca i32, align 4
|
||||
// CHECK-RV32-NEXT: store bfloat [[A]], ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT1]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP0]], ptr [[A1]], align 2
|
||||
// CHECK-RV32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT1]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV32-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[COERCE_DIVE_COERCE]], ptr align 2 [[COERCE_DIVE]], i32 2, i1 false)
|
||||
// CHECK-RV32-NEXT: [[TMP1:%.*]] = load i32, ptr [[COERCE_DIVE_COERCE]], align 4
|
||||
// CHECK-RV32-NEXT: ret i32 [[TMP1]]
|
||||
//
|
||||
struct bfloat1 h1(__bf16 a) {
|
||||
struct bfloat1 x;
|
||||
x.a = a;
|
||||
return x;
|
||||
}
|
||||
|
||||
struct bfloat2 {
|
||||
__bf16 a;
|
||||
__bf16 b;
|
||||
};
|
||||
|
||||
// CHECK-RV64-LABEL: define dso_local i64 @h2
|
||||
// CHECK-RV64-SAME: (bfloat noundef [[A:%.*]], bfloat noundef [[B:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV64-NEXT: entry:
|
||||
// CHECK-RV64-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_BFLOAT2:%.*]], align 2
|
||||
// CHECK-RV64-NEXT: [[A_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[RETVAL_COERCE:%.*]] = alloca i64, align 8
|
||||
// CHECK-RV64-NEXT: store bfloat [[A]], ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT2]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP0]], ptr [[A1]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT2]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 2
|
||||
// CHECK-RV64-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL_COERCE]], ptr align 2 [[RETVAL]], i64 4, i1 false)
|
||||
// CHECK-RV64-NEXT: [[TMP2:%.*]] = load i64, ptr [[RETVAL_COERCE]], align 8
|
||||
// CHECK-RV64-NEXT: ret i64 [[TMP2]]
|
||||
//
|
||||
// CHECK-RV32-LABEL: define dso_local i32 @h2
|
||||
// CHECK-RV32-SAME: (bfloat noundef [[A:%.*]], bfloat noundef [[B:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV32-NEXT: entry:
|
||||
// CHECK-RV32-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_BFLOAT2:%.*]], align 2
|
||||
// CHECK-RV32-NEXT: [[A_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[A]], ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT2]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP0]], ptr [[A1]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT2]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP2:%.*]] = load i32, ptr [[RETVAL]], align 2
|
||||
// CHECK-RV32-NEXT: ret i32 [[TMP2]]
|
||||
//
|
||||
struct bfloat2 h2(__bf16 a, __bf16 b) {
|
||||
struct bfloat2 x;
|
||||
x.a = a;
|
||||
x.b = b;
|
||||
return x;
|
||||
}
|
||||
|
||||
struct bfloat3 {
|
||||
__bf16 a;
|
||||
__bf16 b;
|
||||
__bf16 c;
|
||||
};
|
||||
|
||||
// CHECK-RV64-LABEL: define dso_local i64 @h3
|
||||
// CHECK-RV64-SAME: (bfloat noundef [[A:%.*]], bfloat noundef [[B:%.*]], bfloat noundef [[C:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV64-NEXT: entry:
|
||||
// CHECK-RV64-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_BFLOAT3:%.*]], align 2
|
||||
// CHECK-RV64-NEXT: [[A_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[C_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[RETVAL_COERCE:%.*]] = alloca i64, align 8
|
||||
// CHECK-RV64-NEXT: store bfloat [[A]], ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[C]], ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT3]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP0]], ptr [[A1]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT3]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP2:%.*]] = load bfloat, ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[C3:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT3]], ptr [[RETVAL]], i32 0, i32 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP2]], ptr [[C3]], align 2
|
||||
// CHECK-RV64-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL_COERCE]], ptr align 2 [[RETVAL]], i64 6, i1 false)
|
||||
// CHECK-RV64-NEXT: [[TMP3:%.*]] = load i64, ptr [[RETVAL_COERCE]], align 8
|
||||
// CHECK-RV64-NEXT: ret i64 [[TMP3]]
|
||||
//
|
||||
// CHECK-RV32-LABEL: define dso_local [2 x i32] @h3
|
||||
// CHECK-RV32-SAME: (bfloat noundef [[A:%.*]], bfloat noundef [[B:%.*]], bfloat noundef [[C:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV32-NEXT: entry:
|
||||
// CHECK-RV32-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_BFLOAT3:%.*]], align 2
|
||||
// CHECK-RV32-NEXT: [[A_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[C_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[RETVAL_COERCE:%.*]] = alloca [2 x i32], align 4
|
||||
// CHECK-RV32-NEXT: store bfloat [[A]], ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[C]], ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT3]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP0]], ptr [[A1]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT3]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP2:%.*]] = load bfloat, ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[C3:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT3]], ptr [[RETVAL]], i32 0, i32 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP2]], ptr [[C3]], align 2
|
||||
// CHECK-RV32-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[RETVAL_COERCE]], ptr align 2 [[RETVAL]], i32 6, i1 false)
|
||||
// CHECK-RV32-NEXT: [[TMP3:%.*]] = load [2 x i32], ptr [[RETVAL_COERCE]], align 4
|
||||
// CHECK-RV32-NEXT: ret [2 x i32] [[TMP3]]
|
||||
//
|
||||
struct bfloat3 h3(__bf16 a, __bf16 b, __bf16 c) {
|
||||
struct bfloat3 x;
|
||||
x.a = a;
|
||||
x.b = b;
|
||||
x.c = c;
|
||||
return x;
|
||||
}
|
||||
|
||||
struct bfloat4 {
|
||||
__bf16 a;
|
||||
__bf16 b;
|
||||
__bf16 c;
|
||||
__bf16 d;
|
||||
};
|
||||
|
||||
// CHECK-RV64-LABEL: define dso_local i64 @h4
|
||||
// CHECK-RV64-SAME: (bfloat noundef [[A:%.*]], bfloat noundef [[B:%.*]], bfloat noundef [[C:%.*]], bfloat noundef [[D:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV64-NEXT: entry:
|
||||
// CHECK-RV64-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_BFLOAT4:%.*]], align 2
|
||||
// CHECK-RV64-NEXT: [[A_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[C_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[D_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[A]], ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[C]], ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[D]], ptr [[D_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT4]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP0]], ptr [[A1]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT4]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP2:%.*]] = load bfloat, ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[C3:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT4]], ptr [[RETVAL]], i32 0, i32 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP2]], ptr [[C3]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP3:%.*]] = load bfloat, ptr [[D_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[D4:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT4]], ptr [[RETVAL]], i32 0, i32 3
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP3]], ptr [[D4]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP4:%.*]] = load i64, ptr [[RETVAL]], align 2
|
||||
// CHECK-RV64-NEXT: ret i64 [[TMP4]]
|
||||
//
|
||||
// CHECK-RV32-LABEL: define dso_local [2 x i32] @h4
|
||||
// CHECK-RV32-SAME: (bfloat noundef [[A:%.*]], bfloat noundef [[B:%.*]], bfloat noundef [[C:%.*]], bfloat noundef [[D:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV32-NEXT: entry:
|
||||
// CHECK-RV32-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_BFLOAT4:%.*]], align 2
|
||||
// CHECK-RV32-NEXT: [[A_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[C_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[D_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[A]], ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[C]], ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[D]], ptr [[D_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT4]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP0]], ptr [[A1]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT4]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP2:%.*]] = load bfloat, ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[C3:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT4]], ptr [[RETVAL]], i32 0, i32 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP2]], ptr [[C3]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP3:%.*]] = load bfloat, ptr [[D_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[D4:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT4]], ptr [[RETVAL]], i32 0, i32 3
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP3]], ptr [[D4]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP4:%.*]] = load [2 x i32], ptr [[RETVAL]], align 2
|
||||
// CHECK-RV32-NEXT: ret [2 x i32] [[TMP4]]
|
||||
//
|
||||
struct bfloat4 h4(__bf16 a, __bf16 b, __bf16 c, __bf16 d) {
|
||||
struct bfloat4 x;
|
||||
x.a = a;
|
||||
x.b = b;
|
||||
x.c = c;
|
||||
x.d = d;
|
||||
return x;
|
||||
}
|
||||
|
||||
struct floatbfloat {
|
||||
float a;
|
||||
__bf16 b;
|
||||
};
|
||||
|
||||
// CHECK-RV64-LABEL: define dso_local i64 @fh
|
||||
// CHECK-RV64-SAME: (float noundef [[A:%.*]], bfloat noundef [[B:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV64-NEXT: entry:
|
||||
// CHECK-RV64-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_FLOATBFLOAT:%.*]], align 4
|
||||
// CHECK-RV64-NEXT: [[A_ADDR:%.*]] = alloca float, align 4
|
||||
// CHECK-RV64-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: store float [[A]], ptr [[A_ADDR]], align 4
|
||||
// CHECK-RV64-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP0:%.*]] = load float, ptr [[A_ADDR]], align 4
|
||||
// CHECK-RV64-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV64-NEXT: store float [[TMP0]], ptr [[A1]], align 4
|
||||
// CHECK-RV64-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 4
|
||||
// CHECK-RV64-NEXT: [[TMP2:%.*]] = load i64, ptr [[RETVAL]], align 4
|
||||
// CHECK-RV64-NEXT: ret i64 [[TMP2]]
|
||||
//
|
||||
// CHECK-RV32-LABEL: define dso_local [2 x i32] @fh
|
||||
// CHECK-RV32-SAME: (float noundef [[A:%.*]], bfloat noundef [[B:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV32-NEXT: entry:
|
||||
// CHECK-RV32-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_FLOATBFLOAT:%.*]], align 4
|
||||
// CHECK-RV32-NEXT: [[A_ADDR:%.*]] = alloca float, align 4
|
||||
// CHECK-RV32-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: store float [[A]], ptr [[A_ADDR]], align 4
|
||||
// CHECK-RV32-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP0:%.*]] = load float, ptr [[A_ADDR]], align 4
|
||||
// CHECK-RV32-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV32-NEXT: store float [[TMP0]], ptr [[A1]], align 4
|
||||
// CHECK-RV32-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 4
|
||||
// CHECK-RV32-NEXT: [[TMP2:%.*]] = load [2 x i32], ptr [[RETVAL]], align 4
|
||||
// CHECK-RV32-NEXT: ret [2 x i32] [[TMP2]]
|
||||
//
|
||||
struct floatbfloat fh(float a, __bf16 b) {
|
||||
struct floatbfloat x;
|
||||
x.a = a;
|
||||
x.b = b;
|
||||
return x;
|
||||
}
|
||||
|
||||
struct floatbfloat2 {
|
||||
float a;
|
||||
__bf16 b;
|
||||
__bf16 c;
|
||||
};
|
||||
|
||||
// CHECK-RV64-LABEL: define dso_local i64 @fh2
|
||||
// CHECK-RV64-SAME: (float noundef [[A:%.*]], bfloat noundef [[B:%.*]], bfloat noundef [[C:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV64-NEXT: entry:
|
||||
// CHECK-RV64-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_FLOATBFLOAT2:%.*]], align 4
|
||||
// CHECK-RV64-NEXT: [[A_ADDR:%.*]] = alloca float, align 4
|
||||
// CHECK-RV64-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[C_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: store float [[A]], ptr [[A_ADDR]], align 4
|
||||
// CHECK-RV64-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[C]], ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP0:%.*]] = load float, ptr [[A_ADDR]], align 4
|
||||
// CHECK-RV64-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT2]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV64-NEXT: store float [[TMP0]], ptr [[A1]], align 4
|
||||
// CHECK-RV64-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT2]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 4
|
||||
// CHECK-RV64-NEXT: [[TMP2:%.*]] = load bfloat, ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[C3:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT2]], ptr [[RETVAL]], i32 0, i32 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP2]], ptr [[C3]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP3:%.*]] = load i64, ptr [[RETVAL]], align 4
|
||||
// CHECK-RV64-NEXT: ret i64 [[TMP3]]
|
||||
//
|
||||
// CHECK-RV32-LABEL: define dso_local [2 x i32] @fh2
|
||||
// CHECK-RV32-SAME: (float noundef [[A:%.*]], bfloat noundef [[B:%.*]], bfloat noundef [[C:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV32-NEXT: entry:
|
||||
// CHECK-RV32-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_FLOATBFLOAT2:%.*]], align 4
|
||||
// CHECK-RV32-NEXT: [[A_ADDR:%.*]] = alloca float, align 4
|
||||
// CHECK-RV32-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[C_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: store float [[A]], ptr [[A_ADDR]], align 4
|
||||
// CHECK-RV32-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[C]], ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP0:%.*]] = load float, ptr [[A_ADDR]], align 4
|
||||
// CHECK-RV32-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT2]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV32-NEXT: store float [[TMP0]], ptr [[A1]], align 4
|
||||
// CHECK-RV32-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT2]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 4
|
||||
// CHECK-RV32-NEXT: [[TMP2:%.*]] = load bfloat, ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[C3:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT2]], ptr [[RETVAL]], i32 0, i32 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP2]], ptr [[C3]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP3:%.*]] = load [2 x i32], ptr [[RETVAL]], align 4
|
||||
// CHECK-RV32-NEXT: ret [2 x i32] [[TMP3]]
|
||||
//
|
||||
struct floatbfloat2 fh2(float a, __bf16 b, __bf16 c) {
|
||||
struct floatbfloat2 x;
|
||||
x.a = a;
|
||||
x.b = b;
|
||||
x.c = c;
|
||||
return x;
|
||||
}
|
||||
|
||||
struct bfloatfloat {
|
||||
__bf16 a;
|
||||
float b;
|
||||
};
|
||||
|
||||
// CHECK-RV64-LABEL: define dso_local i64 @hf
|
||||
// CHECK-RV64-SAME: (bfloat noundef [[A:%.*]], float noundef [[B:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV64-NEXT: entry:
|
||||
// CHECK-RV64-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_BFLOATFLOAT:%.*]], align 4
|
||||
// CHECK-RV64-NEXT: [[A_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[B_ADDR:%.*]] = alloca float, align 4
|
||||
// CHECK-RV64-NEXT: store bfloat [[A]], ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store float [[B]], ptr [[B_ADDR]], align 4
|
||||
// CHECK-RV64-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_BFLOATFLOAT]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP0]], ptr [[A1]], align 4
|
||||
// CHECK-RV64-NEXT: [[TMP1:%.*]] = load float, ptr [[B_ADDR]], align 4
|
||||
// CHECK-RV64-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_BFLOATFLOAT]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV64-NEXT: store float [[TMP1]], ptr [[B2]], align 4
|
||||
// CHECK-RV64-NEXT: [[TMP2:%.*]] = load i64, ptr [[RETVAL]], align 4
|
||||
// CHECK-RV64-NEXT: ret i64 [[TMP2]]
|
||||
//
|
||||
// CHECK-RV32-LABEL: define dso_local [2 x i32] @hf
|
||||
// CHECK-RV32-SAME: (bfloat noundef [[A:%.*]], float noundef [[B:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV32-NEXT: entry:
|
||||
// CHECK-RV32-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_BFLOATFLOAT:%.*]], align 4
|
||||
// CHECK-RV32-NEXT: [[A_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[B_ADDR:%.*]] = alloca float, align 4
|
||||
// CHECK-RV32-NEXT: store bfloat [[A]], ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store float [[B]], ptr [[B_ADDR]], align 4
|
||||
// CHECK-RV32-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_BFLOATFLOAT]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP0]], ptr [[A1]], align 4
|
||||
// CHECK-RV32-NEXT: [[TMP1:%.*]] = load float, ptr [[B_ADDR]], align 4
|
||||
// CHECK-RV32-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_BFLOATFLOAT]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV32-NEXT: store float [[TMP1]], ptr [[B2]], align 4
|
||||
// CHECK-RV32-NEXT: [[TMP2:%.*]] = load [2 x i32], ptr [[RETVAL]], align 4
|
||||
// CHECK-RV32-NEXT: ret [2 x i32] [[TMP2]]
|
||||
//
|
||||
struct bfloatfloat hf(__bf16 a, float b) {
|
||||
struct bfloatfloat x;
|
||||
x.a = a;
|
||||
x.b = b;
|
||||
return x;
|
||||
}
|
||||
|
||||
struct bfloat2float {
|
||||
__bf16 a;
|
||||
__bf16 b;
|
||||
float c;
|
||||
};
|
||||
|
||||
// CHECK-RV64-LABEL: define dso_local i64 @h2f
|
||||
// CHECK-RV64-SAME: (bfloat noundef [[A:%.*]], bfloat noundef [[B:%.*]], float noundef [[C:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV64-NEXT: entry:
|
||||
// CHECK-RV64-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_BFLOAT2FLOAT:%.*]], align 4
|
||||
// CHECK-RV64-NEXT: [[A_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[C_ADDR:%.*]] = alloca float, align 4
|
||||
// CHECK-RV64-NEXT: store bfloat [[A]], ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store float [[C]], ptr [[C_ADDR]], align 4
|
||||
// CHECK-RV64-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT2FLOAT]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP0]], ptr [[A1]], align 4
|
||||
// CHECK-RV64-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT2FLOAT]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP2:%.*]] = load float, ptr [[C_ADDR]], align 4
|
||||
// CHECK-RV64-NEXT: [[C3:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT2FLOAT]], ptr [[RETVAL]], i32 0, i32 2
|
||||
// CHECK-RV64-NEXT: store float [[TMP2]], ptr [[C3]], align 4
|
||||
// CHECK-RV64-NEXT: [[TMP3:%.*]] = load i64, ptr [[RETVAL]], align 4
|
||||
// CHECK-RV64-NEXT: ret i64 [[TMP3]]
|
||||
//
|
||||
// CHECK-RV32-LABEL: define dso_local [2 x i32] @h2f
|
||||
// CHECK-RV32-SAME: (bfloat noundef [[A:%.*]], bfloat noundef [[B:%.*]], float noundef [[C:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV32-NEXT: entry:
|
||||
// CHECK-RV32-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_BFLOAT2FLOAT:%.*]], align 4
|
||||
// CHECK-RV32-NEXT: [[A_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[C_ADDR:%.*]] = alloca float, align 4
|
||||
// CHECK-RV32-NEXT: store bfloat [[A]], ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store float [[C]], ptr [[C_ADDR]], align 4
|
||||
// CHECK-RV32-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT2FLOAT]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP0]], ptr [[A1]], align 4
|
||||
// CHECK-RV32-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT2FLOAT]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP2:%.*]] = load float, ptr [[C_ADDR]], align 4
|
||||
// CHECK-RV32-NEXT: [[C3:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT2FLOAT]], ptr [[RETVAL]], i32 0, i32 2
|
||||
// CHECK-RV32-NEXT: store float [[TMP2]], ptr [[C3]], align 4
|
||||
// CHECK-RV32-NEXT: [[TMP3:%.*]] = load [2 x i32], ptr [[RETVAL]], align 4
|
||||
// CHECK-RV32-NEXT: ret [2 x i32] [[TMP3]]
|
||||
//
|
||||
struct bfloat2float h2f(__bf16 a, __bf16 b, float c) {
|
||||
struct bfloat2float x;
|
||||
x.a = a;
|
||||
x.b = b;
|
||||
x.c = c;
|
||||
return x;
|
||||
}
|
||||
|
||||
struct floatbfloat3 {
|
||||
float a;
|
||||
__bf16 b;
|
||||
__bf16 c;
|
||||
__bf16 d;
|
||||
};
|
||||
|
||||
// CHECK-RV64-LABEL: define dso_local [2 x i64] @fh3
|
||||
// CHECK-RV64-SAME: (float noundef [[A:%.*]], bfloat noundef [[B:%.*]], bfloat noundef [[C:%.*]], bfloat noundef [[D:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV64-NEXT: entry:
|
||||
// CHECK-RV64-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_FLOATBFLOAT3:%.*]], align 4
|
||||
// CHECK-RV64-NEXT: [[A_ADDR:%.*]] = alloca float, align 4
|
||||
// CHECK-RV64-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[C_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[D_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[RETVAL_COERCE:%.*]] = alloca [2 x i64], align 8
|
||||
// CHECK-RV64-NEXT: store float [[A]], ptr [[A_ADDR]], align 4
|
||||
// CHECK-RV64-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[C]], ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[D]], ptr [[D_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP0:%.*]] = load float, ptr [[A_ADDR]], align 4
|
||||
// CHECK-RV64-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT3]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV64-NEXT: store float [[TMP0]], ptr [[A1]], align 4
|
||||
// CHECK-RV64-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT3]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 4
|
||||
// CHECK-RV64-NEXT: [[TMP2:%.*]] = load bfloat, ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[C3:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT3]], ptr [[RETVAL]], i32 0, i32 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP2]], ptr [[C3]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP3:%.*]] = load bfloat, ptr [[D_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[D4:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT3]], ptr [[RETVAL]], i32 0, i32 3
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP3]], ptr [[D4]], align 4
|
||||
// CHECK-RV64-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL_COERCE]], ptr align 4 [[RETVAL]], i64 12, i1 false)
|
||||
// CHECK-RV64-NEXT: [[TMP4:%.*]] = load [2 x i64], ptr [[RETVAL_COERCE]], align 8
|
||||
// CHECK-RV64-NEXT: ret [2 x i64] [[TMP4]]
|
||||
//
|
||||
// CHECK-RV32-LABEL: define dso_local void @fh3
|
||||
// CHECK-RV32-SAME: (ptr noalias sret([[STRUCT_FLOATBFLOAT3:%.*]]) align 4 [[AGG_RESULT:%.*]], float noundef [[A:%.*]], bfloat noundef [[B:%.*]], bfloat noundef [[C:%.*]], bfloat noundef [[D:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV32-NEXT: entry:
|
||||
// CHECK-RV32-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
|
||||
// CHECK-RV32-NEXT: [[A_ADDR:%.*]] = alloca float, align 4
|
||||
// CHECK-RV32-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[C_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[D_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: store ptr [[AGG_RESULT]], ptr [[RESULT_PTR]], align 4
|
||||
// CHECK-RV32-NEXT: store float [[A]], ptr [[A_ADDR]], align 4
|
||||
// CHECK-RV32-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[C]], ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[D]], ptr [[D_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP0:%.*]] = load float, ptr [[A_ADDR]], align 4
|
||||
// CHECK-RV32-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT3]], ptr [[AGG_RESULT]], i32 0, i32 0
|
||||
// CHECK-RV32-NEXT: store float [[TMP0]], ptr [[A1]], align 4
|
||||
// CHECK-RV32-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT3]], ptr [[AGG_RESULT]], i32 0, i32 1
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 4
|
||||
// CHECK-RV32-NEXT: [[TMP2:%.*]] = load bfloat, ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[C3:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT3]], ptr [[AGG_RESULT]], i32 0, i32 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP2]], ptr [[C3]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP3:%.*]] = load bfloat, ptr [[D_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[D4:%.*]] = getelementptr inbounds [[STRUCT_FLOATBFLOAT3]], ptr [[AGG_RESULT]], i32 0, i32 3
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP3]], ptr [[D4]], align 4
|
||||
// CHECK-RV32-NEXT: ret void
|
||||
//
|
||||
struct floatbfloat3 fh3(float a, __bf16 b, __bf16 c, __bf16 d) {
|
||||
struct floatbfloat3 x;
|
||||
x.a = a;
|
||||
x.b = b;
|
||||
x.c = c;
|
||||
x.d = d;
|
||||
return x;
|
||||
}
|
||||
|
||||
struct bfloat5 {
|
||||
__bf16 a;
|
||||
__bf16 b;
|
||||
__bf16 c;
|
||||
__bf16 d;
|
||||
__bf16 e;
|
||||
};
|
||||
|
||||
// CHECK-RV64-LABEL: define dso_local [2 x i64] @h5
|
||||
// CHECK-RV64-SAME: (bfloat noundef [[A:%.*]], bfloat noundef [[B:%.*]], bfloat noundef [[C:%.*]], bfloat noundef [[D:%.*]], bfloat noundef [[E:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV64-NEXT: entry:
|
||||
// CHECK-RV64-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_BFLOAT5:%.*]], align 2
|
||||
// CHECK-RV64-NEXT: [[A_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[C_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[D_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[E_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: [[RETVAL_COERCE:%.*]] = alloca [2 x i64], align 8
|
||||
// CHECK-RV64-NEXT: store bfloat [[A]], ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[C]], ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[D]], ptr [[D_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[E]], ptr [[E_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT5]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP0]], ptr [[A1]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT5]], ptr [[RETVAL]], i32 0, i32 1
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP2:%.*]] = load bfloat, ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[C3:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT5]], ptr [[RETVAL]], i32 0, i32 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP2]], ptr [[C3]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP3:%.*]] = load bfloat, ptr [[D_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[D4:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT5]], ptr [[RETVAL]], i32 0, i32 3
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP3]], ptr [[D4]], align 2
|
||||
// CHECK-RV64-NEXT: [[TMP4:%.*]] = load bfloat, ptr [[E_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: [[E5:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT5]], ptr [[RETVAL]], i32 0, i32 4
|
||||
// CHECK-RV64-NEXT: store bfloat [[TMP4]], ptr [[E5]], align 2
|
||||
// CHECK-RV64-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL_COERCE]], ptr align 2 [[RETVAL]], i64 10, i1 false)
|
||||
// CHECK-RV64-NEXT: [[TMP5:%.*]] = load [2 x i64], ptr [[RETVAL_COERCE]], align 8
|
||||
// CHECK-RV64-NEXT: ret [2 x i64] [[TMP5]]
|
||||
//
|
||||
// CHECK-RV32-LABEL: define dso_local void @h5
|
||||
// CHECK-RV32-SAME: (ptr noalias sret([[STRUCT_BFLOAT5:%.*]]) align 2 [[AGG_RESULT:%.*]], bfloat noundef [[A:%.*]], bfloat noundef [[B:%.*]], bfloat noundef [[C:%.*]], bfloat noundef [[D:%.*]], bfloat noundef [[E:%.*]]) #[[ATTR0]] {
|
||||
// CHECK-RV32-NEXT: entry:
|
||||
// CHECK-RV32-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
|
||||
// CHECK-RV32-NEXT: [[A_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[C_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[D_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: [[E_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: store ptr [[AGG_RESULT]], ptr [[RESULT_PTR]], align 4
|
||||
// CHECK-RV32-NEXT: store bfloat [[A]], ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[C]], ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[D]], ptr [[D_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[E]], ptr [[E_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP0:%.*]] = load bfloat, ptr [[A_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[A1:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT5]], ptr [[AGG_RESULT]], i32 0, i32 0
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP0]], ptr [[A1]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP1:%.*]] = load bfloat, ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[B2:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT5]], ptr [[AGG_RESULT]], i32 0, i32 1
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP1]], ptr [[B2]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP2:%.*]] = load bfloat, ptr [[C_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[C3:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT5]], ptr [[AGG_RESULT]], i32 0, i32 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP2]], ptr [[C3]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP3:%.*]] = load bfloat, ptr [[D_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[D4:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT5]], ptr [[AGG_RESULT]], i32 0, i32 3
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP3]], ptr [[D4]], align 2
|
||||
// CHECK-RV32-NEXT: [[TMP4:%.*]] = load bfloat, ptr [[E_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: [[E5:%.*]] = getelementptr inbounds [[STRUCT_BFLOAT5]], ptr [[AGG_RESULT]], i32 0, i32 4
|
||||
// CHECK-RV32-NEXT: store bfloat [[TMP4]], ptr [[E5]], align 2
|
||||
// CHECK-RV32-NEXT: ret void
|
||||
//
|
||||
struct bfloat5 h5(__bf16 a, __bf16 b, __bf16 c, __bf16 d, __bf16 e) {
|
||||
struct bfloat5 x;
|
||||
x.a = a;
|
||||
x.b = b;
|
||||
x.c = c;
|
||||
x.d = d;
|
||||
x.e = e;
|
||||
return x;
|
||||
}
|
19
clang/test/CodeGen/RISCV/bfloat-mangle.cpp
Normal file
19
clang/test/CodeGen/RISCV/bfloat-mangle.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2
|
||||
// RUN: %clang_cc1 -triple riscv64 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK-RV64
|
||||
// RUN: %clang_cc1 -triple riscv32 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK-RV32
|
||||
|
||||
// CHECK-RV64-LABEL: define dso_local void @_Z3fooDF16b
|
||||
// CHECK-RV64-SAME: (bfloat noundef [[B:%.*]]) #[[ATTR0:[0-9]+]] {
|
||||
// CHECK-RV64-NEXT: entry:
|
||||
// CHECK-RV64-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV64-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV64-NEXT: ret void
|
||||
//
|
||||
// CHECK-RV32-LABEL: define dso_local void @_Z3fooDF16b
|
||||
// CHECK-RV32-SAME: (bfloat noundef [[B:%.*]]) #[[ATTR0:[0-9]+]] {
|
||||
// CHECK-RV32-NEXT: entry:
|
||||
// CHECK-RV32-NEXT: [[B_ADDR:%.*]] = alloca bfloat, align 2
|
||||
// CHECK-RV32-NEXT: store bfloat [[B]], ptr [[B_ADDR]], align 2
|
||||
// CHECK-RV32-NEXT: ret void
|
||||
//
|
||||
void foo(__bf16 b) {}
|
@ -1,7 +0,0 @@
|
||||
// RUN: %clang_cc1 %s -fsyntax-only -verify -triple riscv64-unknown-unknown
|
||||
|
||||
// GH50171
|
||||
// This would previously crash when __bf16 was not a supported type.
|
||||
__bf16 v64bf __attribute__((vector_size(128))); // expected-error {{__bf16 is not supported on this target}} \
|
||||
expected-error {{vector size not an integral multiple of component size}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user