[clang] a5791bf - [RISCV][BF16] Enable __bf16 for riscv targets

Jun Sha via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 31 22:59:14 PDT 2023


Author: Jun Sha (Joshua)
Date: 2023-08-01T13:59:27+08:00
New Revision: a5791bfef4e4bcc159ef9bf40d88262e5f409766

URL: https://github.com/llvm/llvm-project/commit/a5791bfef4e4bcc159ef9bf40d88262e5f409766
DIFF: https://github.com/llvm/llvm-project/commit/a5791bfef4e4bcc159ef9bf40d88262e5f409766.diff

LOG: [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

Added: 
    clang/test/CodeGen/RISCV/bfloat-abi.c
    clang/test/CodeGen/RISCV/bfloat-mangle.cpp

Modified: 
    clang/docs/LanguageExtensions.rst
    clang/lib/Basic/Targets/RISCV.h

Removed: 
    clang/test/Sema/vector-decl-crash.c


################################################################################
diff  --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index fbe240dd79b8484..be80751b40668a3 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -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.)

diff  --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h
index e4e39506bccf5ca..6be0e49ca2f5525 100644
--- a/clang/lib/Basic/Targets/RISCV.h
+++ b/clang/lib/Basic/Targets/RISCV.h
@@ -32,6 +32,9 @@ class RISCVTargetInfo : public TargetInfo {
 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 @@ class RISCVTargetInfo : public TargetInfo {
 
   bool hasBitIntType() const override { return true; }
 
+  bool hasBFloat16Type() const override { return true; }
+
   bool useFP16ConversionIntrinsics() const override {
     return false;
   }

diff  --git a/clang/test/CodeGen/RISCV/bfloat-abi.c b/clang/test/CodeGen/RISCV/bfloat-abi.c
new file mode 100644
index 000000000000000..bfaf1043133b80b
--- /dev/null
+++ b/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;
+}

diff  --git a/clang/test/CodeGen/RISCV/bfloat-mangle.cpp b/clang/test/CodeGen/RISCV/bfloat-mangle.cpp
new file mode 100644
index 000000000000000..7cfa80358e32cdf
--- /dev/null
+++ b/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) {}

diff  --git a/clang/test/Sema/vector-decl-crash.c b/clang/test/Sema/vector-decl-crash.c
deleted file mode 100644
index fafe34133de43d4..000000000000000
--- a/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}}
-


        


More information about the cfe-commits mailing list