| // 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 dead_on_unwind noalias writable 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 dead_on_unwind noalias writable 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; |
| } |