Index: clang/docs/LanguageExtensions.rst =================================================================== --- clang/docs/LanguageExtensions.rst +++ clang/docs/LanguageExtensions.rst @@ -798,7 +798,7 @@ * 32-bit ARM * 64-bit ARM (AArch64) * X86 (when SSE2 is available) - + * RISC-V (For X86, SSE2 is available on 64-bit and all recent 32-bit processors.) ``__fp16`` and ``_Float16`` both use the binary16 format from IEEE Index: clang/lib/Basic/Targets/RISCV.h =================================================================== --- clang/lib/Basic/Targets/RISCV.h +++ clang/lib/Basic/Targets/RISCV.h @@ -32,6 +32,9 @@ 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 @@ bool hasBitIntType() const override { return true; } + bool hasBFloat16Type() const override { return true; } + bool useFP16ConversionIntrinsics() const override { return false; } Index: clang/test/CodeGen/RISCV/bfloat-abi.c =================================================================== --- /dev/null +++ clang/test/CodeGen/RISCV/bfloat-abi.c @@ -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; +} Index: clang/test/CodeGen/RISCV/bfloat-mangle.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/RISCV/bfloat-mangle.cpp @@ -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) {} Index: clang/test/Sema/vector-decl-crash.c =================================================================== --- clang/test/Sema/vector-decl-crash.c +++ /dev/null @@ -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}} -