100 changes: 100 additions & 0 deletions clang/test/CodeGen/attr-riscv-rvv-vector-bits-bitcast.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,29 @@ typedef __rvv_uint64m1_t vuint64m1_t;
typedef __rvv_float32m1_t vfloat32m1_t;
typedef __rvv_float64m1_t vfloat64m1_t;

typedef __rvv_bool1_t vbool1_t;
typedef __rvv_bool2_t vbool2_t;
typedef __rvv_bool4_t vbool4_t;
typedef __rvv_bool8_t vbool8_t;
typedef __rvv_bool16_t vbool16_t;
typedef __rvv_bool32_t vbool32_t;
typedef __rvv_bool64_t vbool64_t;

typedef vint64m1_t fixed_int64m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vfloat64m1_t fixed_float64m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool1_t fixed_bool1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool2_t fixed_bool2_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 2)));
typedef vbool4_t fixed_bool4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 4)));
typedef vbool8_t fixed_bool8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 8)));
#if __riscv_v_fixed_vlen >= 128
typedef vbool16_t fixed_bool16_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 16)));
#endif
#if __riscv_v_fixed_vlen >= 256
typedef vbool32_t fixed_bool32_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 32)));
#endif
#if __riscv_v_fixed_vlen >= 512
typedef vbool64_t fixed_bool64_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 64)));
#endif

#define DEFINE_STRUCT(ty) \
struct struct_##ty { \
Expand All @@ -28,6 +49,19 @@ typedef vfloat64m1_t fixed_float64m1_t __attribute__((riscv_rvv_vector_bits(__ri

DEFINE_STRUCT(int64m1)
DEFINE_STRUCT(float64m1)
DEFINE_STRUCT(bool1)
DEFINE_STRUCT(bool2)
DEFINE_STRUCT(bool4)
DEFINE_STRUCT(bool8)
#if __riscv_v_fixed_vlen >= 128
DEFINE_STRUCT(bool16)
#endif
#if __riscv_v_fixed_vlen >= 256
DEFINE_STRUCT(bool32)
#endif
#if __riscv_v_fixed_vlen >= 512
DEFINE_STRUCT(bool64)
#endif

//===----------------------------------------------------------------------===//
// int64
Expand Down Expand Up @@ -136,3 +170,69 @@ vfloat64m1_t read_float64m1(struct struct_float64m1 *s) {
void write_float64m1(struct struct_float64m1 *s, vfloat64m1_t x) {
s->y[0] = x;
}

//===----------------------------------------------------------------------===//
// bool
//===----------------------------------------------------------------------===//

// CHECK-64-LABEL: @read_bool1(
// CHECK-64-NEXT: entry:
// CHECK-64-NEXT: [[SAVED_VALUE:%.*]] = alloca <8 x i8>, align 8
// CHECK-64-NEXT: [[Y:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_BOOL1:%.*]], ptr [[S:%.*]], i64 0, i32 1
// CHECK-64-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[Y]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: store <8 x i8> [[TMP0]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: [[TMP1:%.*]] = load <vscale x 64 x i1>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: ret <vscale x 64 x i1> [[TMP1]]
//
// CHECK-128-LABEL: @read_bool1(
// CHECK-128-NEXT: entry:
// CHECK-128-NEXT: [[SAVED_VALUE:%.*]] = alloca <16 x i8>, align 16
// CHECK-128-NEXT: [[Y:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_BOOL1:%.*]], ptr [[S:%.*]], i64 0, i32 1
// CHECK-128-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[Y]], align 8, !tbaa [[TBAA4]]
// CHECK-128-NEXT: store <16 x i8> [[TMP0]], ptr [[SAVED_VALUE]], align 16, !tbaa [[TBAA4]]
// CHECK-128-NEXT: [[TMP1:%.*]] = load <vscale x 64 x i1>, ptr [[SAVED_VALUE]], align 16, !tbaa [[TBAA4]]
// CHECK-128-NEXT: ret <vscale x 64 x i1> [[TMP1]]
//
// CHECK-256-LABEL: @read_bool1(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[SAVED_VALUE:%.*]] = alloca <32 x i8>, align 32
// CHECK-256-NEXT: [[Y:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_BOOL1:%.*]], ptr [[S:%.*]], i64 0, i32 1
// CHECK-256-NEXT: [[TMP0:%.*]] = load <32 x i8>, ptr [[Y]], align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: store <32 x i8> [[TMP0]], ptr [[SAVED_VALUE]], align 32, !tbaa [[TBAA4]]
// CHECK-256-NEXT: [[TMP1:%.*]] = load <vscale x 64 x i1>, ptr [[SAVED_VALUE]], align 32, !tbaa [[TBAA4]]
// CHECK-256-NEXT: ret <vscale x 64 x i1> [[TMP1]]
//
vbool1_t read_bool1(struct struct_bool1 *s) {
return s->y[0];
}

// CHECK-64-LABEL: @write_bool1(
// CHECK-64-NEXT: entry:
// CHECK-64-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-64-NEXT: store <vscale x 64 x i1> [[X:%.*]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA7:![0-9]+]]
// CHECK-64-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: [[Y:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_BOOL1:%.*]], ptr [[S:%.*]], i64 0, i32 1
// CHECK-64-NEXT: store <8 x i8> [[TMP0]], ptr [[Y]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: ret void
//
// CHECK-128-LABEL: @write_bool1(
// CHECK-128-NEXT: entry:
// CHECK-128-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 64 x i1>, align 16
// CHECK-128-NEXT: store <vscale x 64 x i1> [[X:%.*]], ptr [[SAVED_VALUE]], align 16, !tbaa [[TBAA7:![0-9]+]]
// CHECK-128-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[SAVED_VALUE]], align 16, !tbaa [[TBAA4]]
// CHECK-128-NEXT: [[Y:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_BOOL1:%.*]], ptr [[S:%.*]], i64 0, i32 1
// CHECK-128-NEXT: store <16 x i8> [[TMP0]], ptr [[Y]], align 8, !tbaa [[TBAA4]]
// CHECK-128-NEXT: ret void
//
// CHECK-256-LABEL: @write_bool1(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-256-NEXT: store <vscale x 64 x i1> [[X:%.*]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA7:![0-9]+]]
// CHECK-256-NEXT: [[TMP0:%.*]] = load <32 x i8>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: [[Y:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_BOOL1:%.*]], ptr [[S:%.*]], i64 0, i32 1
// CHECK-256-NEXT: store <32 x i8> [[TMP0]], ptr [[Y]], align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: ret void
//
void write_bool1(struct struct_bool1 *s, vbool1_t x) {
s->y[0] = x;
}
74 changes: 74 additions & 0 deletions clang/test/CodeGen/attr-riscv-rvv-vector-bits-call.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

typedef vint32m1_t fixed_int32m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vfloat64m1_t fixed_float64m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool1_t fixed_bool1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool4_t fixed_bool4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/4)));

//===----------------------------------------------------------------------===//
// Test caller/callee with VLST <-> VLAT
Expand Down Expand Up @@ -66,6 +68,30 @@ fixed_float64m1_t call_float64_ff(fixed_float64m1_t op1, fixed_float64m1_t op2)
return __riscv_vfadd(op1, op2, __riscv_v_fixed_vlen/64);
}

// CHECK-LABEL: @call_bool1_ff(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[SAVED_VALUE4:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[TMP0:%.*]] = tail call <vscale x 64 x i1> @llvm.riscv.vmand.nxv64i1.i64(<vscale x 64 x i1> [[OP1_COERCE:%.*]], <vscale x 64 x i1> [[OP2_COERCE:%.*]], i64 256)
// CHECK-NEXT: store <vscale x 64 x i1> [[TMP0]], ptr [[SAVED_VALUE4]], align 8, !tbaa [[TBAA4:![0-9]+]]
// CHECK-NEXT: [[TMP1:%.*]] = load <32 x i8>, ptr [[SAVED_VALUE4]], align 8, !tbaa [[TBAA8:![0-9]+]]
// CHECK-NEXT: store <32 x i8> [[TMP1]], ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: [[TMP2:%.*]] = load <vscale x 64 x i1>, ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: ret <vscale x 64 x i1> [[TMP2]]
//
fixed_bool1_t call_bool1_ff(fixed_bool1_t op1, fixed_bool1_t op2) {
return __riscv_vmand(op1, op2, __riscv_v_fixed_vlen);
}

// CHECK-LABEL: @call_bool4_ff(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP2:%.*]] = tail call <vscale x 16 x i1> @llvm.riscv.vmand.nxv16i1.i64(<vscale x 16 x i1> [[TMP0:%.*]], <vscale x 16 x i1> [[TMP1:%.*]], i64 64)
// CHECK-NEXT: ret <vscale x 16 x i1> [[TMP2]]
//
fixed_bool4_t call_bool4_ff(fixed_bool4_t op1, fixed_bool4_t op2) {
return __riscv_vmand(op1, op2, __riscv_v_fixed_vlen / 4);
}

//===----------------------------------------------------------------------===//
// fixed, scalable
//===----------------------------------------------------------------------===//
Expand All @@ -88,6 +114,30 @@ fixed_float64m1_t call_float64_fs(fixed_float64m1_t op1, vfloat64m1_t op2) {
return __riscv_vfadd(op1, op2, __riscv_v_fixed_vlen/64);
}

// CHECK-LABEL: @call_bool1_fs(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[SAVED_VALUE2:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[TMP0:%.*]] = tail call <vscale x 64 x i1> @llvm.riscv.vmand.nxv64i1.i64(<vscale x 64 x i1> [[OP1_COERCE:%.*]], <vscale x 64 x i1> [[OP2:%.*]], i64 256)
// CHECK-NEXT: store <vscale x 64 x i1> [[TMP0]], ptr [[SAVED_VALUE2]], align 8, !tbaa [[TBAA4]]
// CHECK-NEXT: [[TMP1:%.*]] = load <32 x i8>, ptr [[SAVED_VALUE2]], align 8, !tbaa [[TBAA8]]
// CHECK-NEXT: store <32 x i8> [[TMP1]], ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: [[TMP2:%.*]] = load <vscale x 64 x i1>, ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: ret <vscale x 64 x i1> [[TMP2]]
//
fixed_bool1_t call_bool1_fs(fixed_bool1_t op1, vbool1_t op2) {
return __riscv_vmand(op1, op2, __riscv_v_fixed_vlen);
}

// CHECK-LABEL: @call_bool4_fs(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP1:%.*]] = tail call <vscale x 16 x i1> @llvm.riscv.vmand.nxv16i1.i64(<vscale x 16 x i1> [[TMP0:%.*]], <vscale x 16 x i1> [[OP2:%.*]], i64 64)
// CHECK-NEXT: ret <vscale x 16 x i1> [[TMP1]]
//
fixed_bool4_t call_bool4_fs(fixed_bool4_t op1, vbool4_t op2) {
return __riscv_vmand(op1, op2, __riscv_v_fixed_vlen / 4);
}

//===----------------------------------------------------------------------===//
// scalable, scalable
//===----------------------------------------------------------------------===//
Expand All @@ -109,3 +159,27 @@ fixed_int32m1_t call_int32_ss(vint32m1_t op1, vint32m1_t op2) {
fixed_float64m1_t call_float64_ss(vfloat64m1_t op1, vfloat64m1_t op2) {
return __riscv_vfadd(op1, op2, __riscv_v_fixed_vlen/64);
}

// CHECK-LABEL: @call_bool1_ss(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[TMP0:%.*]] = tail call <vscale x 64 x i1> @llvm.riscv.vmand.nxv64i1.i64(<vscale x 64 x i1> [[OP1:%.*]], <vscale x 64 x i1> [[OP2:%.*]], i64 256)
// CHECK-NEXT: store <vscale x 64 x i1> [[TMP0]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-NEXT: [[TMP1:%.*]] = load <32 x i8>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA8]]
// CHECK-NEXT: store <32 x i8> [[TMP1]], ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: [[TMP2:%.*]] = load <vscale x 64 x i1>, ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: ret <vscale x 64 x i1> [[TMP2]]
//
fixed_bool1_t call_bool1_ss(vbool1_t op1, vbool1_t op2) {
return __riscv_vmand(op1, op2, __riscv_v_fixed_vlen);
}

// CHECK-LABEL: @call_bool4_ss(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = tail call <vscale x 16 x i1> @llvm.riscv.vmand.nxv16i1.i64(<vscale x 16 x i1> [[OP1:%.*]], <vscale x 16 x i1> [[OP2:%.*]], i64 64)
// CHECK-NEXT: ret <vscale x 16 x i1> [[TMP0]]
//
fixed_bool4_t call_bool4_ss(vbool4_t op1, vbool4_t op2) {
return __riscv_vmand(op1, op2, __riscv_v_fixed_vlen / 4);
}
76 changes: 72 additions & 4 deletions clang/test/CodeGen/attr-riscv-rvv-vector-bits-cast.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,21 @@ typedef __rvv_uint64m1_t vuint64m1_t;
typedef __rvv_float32m1_t vfloat32m1_t;
typedef __rvv_float64m1_t vfloat64m1_t;

typedef __rvv_bool1_t vbool1_t;
typedef __rvv_bool4_t vbool4_t;
typedef __rvv_bool32_t vbool32_t;

typedef vint64m1_t fixed_int64m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vfloat64m1_t fixed_float64m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));

typedef vint32m1_t fixed_int32m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vfloat64m1_t fixed_float64m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef int32_t gnu_int32m1_t __attribute__((vector_size(__riscv_v_fixed_vlen / 8)));

typedef vbool1_t fixed_bool1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool4_t fixed_bool4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/4)));
typedef vbool32_t fixed_bool32_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/32)));

// CHECK-LABEL: @to_vint32m1_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: ret <vscale x 2 x i32> [[TYPE_COERCE:%.*]]
Expand Down Expand Up @@ -55,9 +63,69 @@ fixed_float64m1_t from_vfloat64m1_t(vfloat64m1_t type) {
return type;
}

// CHECK-LABEL: @from_vbool1_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: store <vscale x 64 x i1> [[TYPE:%.*]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4:![0-9]+]]
// CHECK-NEXT: [[TMP0:%.*]] = load <32 x i8>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA8:![0-9]+]]
// CHECK-NEXT: store <32 x i8> [[TMP0]], ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: [[TMP1:%.*]] = load <vscale x 64 x i1>, ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: ret <vscale x 64 x i1> [[TMP1]]
//
fixed_bool1_t from_vbool1_t(vbool1_t type) {
return type;
}

// CHECK-LABEL: @to_vbool1_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: ret <vscale x 64 x i1> [[TYPE_COERCE:%.*]]
//
vbool1_t to_vbool1_t(fixed_bool1_t type) {
return type;
}

// CHECK-LABEL: @from_vbool4_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: ret <vscale x 16 x i1> [[TYPE:%.*]]
//
fixed_bool4_t from_vbool4_t(vbool4_t type) {
return type;
}

// CHECK-LABEL: @to_vbool4_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: ret <vscale x 16 x i1> [[TMP0:%.*]]
//
vbool4_t to_vbool4_t(fixed_bool4_t type) {
return type;
}

// CHECK-LABEL: @from_vbool32_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 2 x i1>, align 1
// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca <vscale x 2 x i1>, align 1
// CHECK-NEXT: store <vscale x 2 x i1> [[TYPE:%.*]], ptr [[SAVED_VALUE]], align 1, !tbaa [[TBAA9:![0-9]+]]
// CHECK-NEXT: [[TMP0:%.*]] = load <1 x i8>, ptr [[SAVED_VALUE]], align 1, !tbaa [[TBAA8]]
// CHECK-NEXT: store <1 x i8> [[TMP0]], ptr [[RETVAL_COERCE]], align 1
// CHECK-NEXT: [[TMP1:%.*]] = load <vscale x 2 x i1>, ptr [[RETVAL_COERCE]], align 1
// CHECK-NEXT: ret <vscale x 2 x i1> [[TMP1]]
//
fixed_bool32_t from_vbool32_t(vbool32_t type) {
return type;
}

// CHECK-LABEL: @to_vbool32_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: ret <vscale x 2 x i1> [[TYPE_COERCE:%.*]]
//
vbool32_t to_vbool32_t(fixed_bool32_t type) {
return type;
}

// CHECK-LABEL: @to_vint32m1_t__from_gnu_int32m1_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TYPE:%.*]] = load <8 x i32>, ptr [[TMP0:%.*]], align 32, !tbaa [[TBAA4:![0-9]+]]
// CHECK-NEXT: [[TYPE:%.*]] = load <8 x i32>, ptr [[TMP0:%.*]], align 32, !tbaa [[TBAA8]]
// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = tail call <vscale x 2 x i32> @llvm.vector.insert.nxv2i32.v8i32(<vscale x 2 x i32> undef, <8 x i32> [[TYPE]], i64 0)
// CHECK-NEXT: ret <vscale x 2 x i32> [[CAST_SCALABLE]]
//
Expand All @@ -68,7 +136,7 @@ vint32m1_t to_vint32m1_t__from_gnu_int32m1_t(gnu_int32m1_t type) {
// CHECK-LABEL: @from_vint32m1_t__to_gnu_int32m1_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[CAST_FIXED:%.*]] = tail call <8 x i32> @llvm.vector.extract.v8i32.nxv2i32(<vscale x 2 x i32> [[TYPE:%.*]], i64 0)
// CHECK-NEXT: store <8 x i32> [[CAST_FIXED]], ptr [[AGG_RESULT:%.*]], align 32, !tbaa [[TBAA4]]
// CHECK-NEXT: store <8 x i32> [[CAST_FIXED]], ptr [[AGG_RESULT:%.*]], align 32, !tbaa [[TBAA8]]
// CHECK-NEXT: ret void
//
gnu_int32m1_t from_vint32m1_t__to_gnu_int32m1_t(vint32m1_t type) {
Expand All @@ -77,7 +145,7 @@ gnu_int32m1_t from_vint32m1_t__to_gnu_int32m1_t(vint32m1_t type) {

// CHECK-LABEL: @to_fixed_int32m1_t__from_gnu_int32m1_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TYPE:%.*]] = load <8 x i32>, ptr [[TMP0:%.*]], align 32, !tbaa [[TBAA4]]
// CHECK-NEXT: [[TYPE:%.*]] = load <8 x i32>, ptr [[TMP0:%.*]], align 32, !tbaa [[TBAA8]]
// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = tail call <vscale x 2 x i32> @llvm.vector.insert.nxv2i32.v8i32(<vscale x 2 x i32> undef, <8 x i32> [[TYPE]], i64 0)
// CHECK-NEXT: ret <vscale x 2 x i32> [[CAST_SCALABLE]]
//
Expand All @@ -88,7 +156,7 @@ fixed_int32m1_t to_fixed_int32m1_t__from_gnu_int32m1_t(gnu_int32m1_t type) {
// CHECK-LABEL: @from_fixed_int32m1_t__to_gnu_int32m1_t(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TYPE:%.*]] = tail call <8 x i32> @llvm.vector.extract.v8i32.nxv2i32(<vscale x 2 x i32> [[TYPE_COERCE:%.*]], i64 0)
// CHECK-NEXT: store <8 x i32> [[TYPE]], ptr [[AGG_RESULT:%.*]], align 32, !tbaa [[TBAA4]]
// CHECK-NEXT: store <8 x i32> [[TYPE]], ptr [[AGG_RESULT:%.*]], align 32, !tbaa [[TBAA8]]
// CHECK-NEXT: ret void
//
gnu_int32m1_t from_fixed_int32m1_t__to_gnu_int32m1_t(fixed_int32m1_t type) {
Expand Down
172 changes: 172 additions & 0 deletions clang/test/CodeGen/attr-riscv-rvv-vector-bits-codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,117 @@ typedef __rvv_uint64m2_t vuint64m2_t;
typedef __rvv_float32m2_t vfloat32m2_t;
typedef __rvv_float64m2_t vfloat64m2_t;

typedef __rvv_bool1_t vbool1_t;
typedef __rvv_bool4_t vbool4_t;
typedef __rvv_bool32_t vbool32_t;

typedef vint32m1_t fixed_int32m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vint32m2_t fixed_int32m2_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen * 2)));
typedef vint16m4_t fixed_int16m4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen * 4)));
typedef vint8m8_t fixed_int8m8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen * 8)));
typedef vbool1_t fixed_bool1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool4_t fixed_bool4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/4)));
typedef vbool32_t fixed_bool32_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/32)));

fixed_int32m1_t global_vec;
fixed_int32m2_t global_vec_m2;
fixed_int8m8_t global_vec_int8m8;
fixed_int16m4_t global_vec_int16m4;
fixed_bool1_t global_bool1;
fixed_bool4_t global_bool4;
fixed_bool32_t global_bool32;

// CHECK-LABEL: @test_bool1(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca <256 x i8>, align 8
// CHECK-NEXT: [[M_ADDR:%.*]] = alloca <vscale x 64 x i1>, align 1
// CHECK-NEXT: [[VEC_ADDR:%.*]] = alloca <vscale x 64 x i8>, align 1
// CHECK-NEXT: [[MASK:%.*]] = alloca <vscale x 64 x i1>, align 1
// CHECK-NEXT: [[SAVED_VALUE:%.*]] = alloca <32 x i8>, align 32
// CHECK-NEXT: store <vscale x 64 x i1> [[M:%.*]], ptr [[M_ADDR]], align 1
// CHECK-NEXT: store <vscale x 64 x i8> [[VEC:%.*]], ptr [[VEC_ADDR]], align 1
// CHECK-NEXT: [[TMP0:%.*]] = load <vscale x 64 x i1>, ptr [[M_ADDR]], align 1
// CHECK-NEXT: [[TMP1:%.*]] = load <32 x i8>, ptr @global_bool1, align 8
// CHECK-NEXT: store <32 x i8> [[TMP1]], ptr [[SAVED_VALUE]], align 32
// CHECK-NEXT: [[TMP2:%.*]] = load <vscale x 64 x i1>, ptr [[SAVED_VALUE]], align 32
// CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 64 x i1> @llvm.riscv.vmand.nxv64i1.i64(<vscale x 64 x i1> [[TMP0]], <vscale x 64 x i1> [[TMP2]], i64 256)
// CHECK-NEXT: store <vscale x 64 x i1> [[TMP3]], ptr [[MASK]], align 1
// CHECK-NEXT: [[TMP4:%.*]] = load <vscale x 64 x i1>, ptr [[MASK]], align 1
// CHECK-NEXT: [[TMP5:%.*]] = load <vscale x 64 x i8>, ptr [[VEC_ADDR]], align 1
// CHECK-NEXT: [[TMP6:%.*]] = load <256 x i8>, ptr @global_vec_int8m8, align 8
// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call <vscale x 64 x i8> @llvm.vector.insert.nxv64i8.v256i8(<vscale x 64 x i8> undef, <256 x i8> [[TMP6]], i64 0)
// CHECK-NEXT: [[TMP7:%.*]] = call <vscale x 64 x i8> @llvm.riscv.vadd.mask.nxv64i8.nxv64i8.i64(<vscale x 64 x i8> poison, <vscale x 64 x i8> [[TMP5]], <vscale x 64 x i8> [[CAST_SCALABLE]], <vscale x 64 x i1> [[TMP4]], i64 256, i64 3)
// CHECK-NEXT: [[CAST_FIXED:%.*]] = call <256 x i8> @llvm.vector.extract.v256i8.nxv64i8(<vscale x 64 x i8> [[TMP7]], i64 0)
// CHECK-NEXT: store <256 x i8> [[CAST_FIXED]], ptr [[RETVAL]], align 8
// CHECK-NEXT: [[TMP8:%.*]] = load <256 x i8>, ptr [[RETVAL]], align 8
// CHECK-NEXT: [[CAST_SCALABLE1:%.*]] = call <vscale x 64 x i8> @llvm.vector.insert.nxv64i8.v256i8(<vscale x 64 x i8> undef, <256 x i8> [[TMP8]], i64 0)
// CHECK-NEXT: ret <vscale x 64 x i8> [[CAST_SCALABLE1]]
//
fixed_int8m8_t test_bool1(vbool1_t m, vint8m8_t vec) {
vbool1_t mask = __riscv_vmand(m, global_bool1, __riscv_v_fixed_vlen);
return __riscv_vadd(mask, vec, global_vec_int8m8, __riscv_v_fixed_vlen);
}

// CHECK-LABEL: @test_bool4(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca <64 x i16>, align 8
// CHECK-NEXT: [[M_ADDR:%.*]] = alloca <vscale x 16 x i1>, align 1
// CHECK-NEXT: [[VEC_ADDR:%.*]] = alloca <vscale x 16 x i16>, align 2
// CHECK-NEXT: [[MASK:%.*]] = alloca <vscale x 16 x i1>, align 1
// CHECK-NEXT: store <vscale x 16 x i1> [[M:%.*]], ptr [[M_ADDR]], align 1
// CHECK-NEXT: store <vscale x 16 x i16> [[VEC:%.*]], ptr [[VEC_ADDR]], align 2
// CHECK-NEXT: [[TMP0:%.*]] = load <vscale x 16 x i1>, ptr [[M_ADDR]], align 1
// CHECK-NEXT: [[TMP1:%.*]] = load <8 x i8>, ptr @global_bool4, align 8
// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call <vscale x 2 x i8> @llvm.vector.insert.nxv2i8.v8i8(<vscale x 2 x i8> undef, <8 x i8> [[TMP1]], i64 0)
// CHECK-NEXT: [[TMP2:%.*]] = bitcast <vscale x 2 x i8> [[CAST_SCALABLE]] to <vscale x 16 x i1>
// CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 16 x i1> @llvm.riscv.vmand.nxv16i1.i64(<vscale x 16 x i1> [[TMP0]], <vscale x 16 x i1> [[TMP2]], i64 64)
// CHECK-NEXT: store <vscale x 16 x i1> [[TMP3]], ptr [[MASK]], align 1
// CHECK-NEXT: [[TMP4:%.*]] = load <vscale x 16 x i1>, ptr [[MASK]], align 1
// CHECK-NEXT: [[TMP5:%.*]] = load <vscale x 16 x i16>, ptr [[VEC_ADDR]], align 2
// CHECK-NEXT: [[TMP6:%.*]] = load <64 x i16>, ptr @global_vec_int16m4, align 8
// CHECK-NEXT: [[CAST_SCALABLE1:%.*]] = call <vscale x 16 x i16> @llvm.vector.insert.nxv16i16.v64i16(<vscale x 16 x i16> undef, <64 x i16> [[TMP6]], i64 0)
// CHECK-NEXT: [[TMP7:%.*]] = call <vscale x 16 x i16> @llvm.riscv.vadd.mask.nxv16i16.nxv16i16.i64(<vscale x 16 x i16> poison, <vscale x 16 x i16> [[TMP5]], <vscale x 16 x i16> [[CAST_SCALABLE1]], <vscale x 16 x i1> [[TMP4]], i64 64, i64 3)
// CHECK-NEXT: [[CAST_FIXED:%.*]] = call <64 x i16> @llvm.vector.extract.v64i16.nxv16i16(<vscale x 16 x i16> [[TMP7]], i64 0)
// CHECK-NEXT: store <64 x i16> [[CAST_FIXED]], ptr [[RETVAL]], align 8
// CHECK-NEXT: [[TMP8:%.*]] = load <64 x i16>, ptr [[RETVAL]], align 8
// CHECK-NEXT: [[CAST_SCALABLE2:%.*]] = call <vscale x 16 x i16> @llvm.vector.insert.nxv16i16.v64i16(<vscale x 16 x i16> undef, <64 x i16> [[TMP8]], i64 0)
// CHECK-NEXT: ret <vscale x 16 x i16> [[CAST_SCALABLE2]]
//
fixed_int16m4_t test_bool4(vbool4_t m, vint16m4_t vec) {
vbool4_t mask = __riscv_vmand(m, global_bool4, __riscv_v_fixed_vlen/4);
return __riscv_vadd(mask, vec, global_vec_int16m4, __riscv_v_fixed_vlen/4);
}

// CHECK-LABEL: @test_bool32(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca <8 x i32>, align 8
// CHECK-NEXT: [[M_ADDR:%.*]] = alloca <vscale x 2 x i1>, align 1
// CHECK-NEXT: [[VEC_ADDR:%.*]] = alloca <vscale x 2 x i32>, align 4
// CHECK-NEXT: [[MASK:%.*]] = alloca <vscale x 2 x i1>, align 1
// CHECK-NEXT: [[SAVED_VALUE:%.*]] = alloca <1 x i8>, align 1
// CHECK-NEXT: store <vscale x 2 x i1> [[M:%.*]], ptr [[M_ADDR]], align 1
// CHECK-NEXT: store <vscale x 2 x i32> [[VEC:%.*]], ptr [[VEC_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load <vscale x 2 x i1>, ptr [[M_ADDR]], align 1
// CHECK-NEXT: [[TMP1:%.*]] = load <1 x i8>, ptr @global_bool32, align 1
// CHECK-NEXT: store <1 x i8> [[TMP1]], ptr [[SAVED_VALUE]], align 1
// CHECK-NEXT: [[TMP2:%.*]] = load <vscale x 2 x i1>, ptr [[SAVED_VALUE]], align 1
// CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 2 x i1> @llvm.riscv.vmand.nxv2i1.i64(<vscale x 2 x i1> [[TMP0]], <vscale x 2 x i1> [[TMP2]], i64 8)
// CHECK-NEXT: store <vscale x 2 x i1> [[TMP3]], ptr [[MASK]], align 1
// CHECK-NEXT: [[TMP4:%.*]] = load <vscale x 2 x i1>, ptr [[MASK]], align 1
// CHECK-NEXT: [[TMP5:%.*]] = load <vscale x 2 x i32>, ptr [[VEC_ADDR]], align 4
// CHECK-NEXT: [[TMP6:%.*]] = load <8 x i32>, ptr @global_vec, align 8
// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call <vscale x 2 x i32> @llvm.vector.insert.nxv2i32.v8i32(<vscale x 2 x i32> undef, <8 x i32> [[TMP6]], i64 0)
// CHECK-NEXT: [[TMP7:%.*]] = call <vscale x 2 x i32> @llvm.riscv.vadd.mask.nxv2i32.nxv2i32.i64(<vscale x 2 x i32> poison, <vscale x 2 x i32> [[TMP5]], <vscale x 2 x i32> [[CAST_SCALABLE]], <vscale x 2 x i1> [[TMP4]], i64 8, i64 3)
// CHECK-NEXT: [[CAST_FIXED:%.*]] = call <8 x i32> @llvm.vector.extract.v8i32.nxv2i32(<vscale x 2 x i32> [[TMP7]], i64 0)
// CHECK-NEXT: store <8 x i32> [[CAST_FIXED]], ptr [[RETVAL]], align 8
// CHECK-NEXT: [[TMP8:%.*]] = load <8 x i32>, ptr [[RETVAL]], align 8
// CHECK-NEXT: [[CAST_SCALABLE1:%.*]] = call <vscale x 2 x i32> @llvm.vector.insert.nxv2i32.v8i32(<vscale x 2 x i32> undef, <8 x i32> [[TMP8]], i64 0)
// CHECK-NEXT: ret <vscale x 2 x i32> [[CAST_SCALABLE1]]
//
fixed_int32m1_t test_bool32(vbool32_t m, vint32m1_t vec) {
vbool32_t mask = __riscv_vmand(m, global_bool32, __riscv_v_fixed_vlen/32);
return __riscv_vadd(mask, vec, global_vec, __riscv_v_fixed_vlen/32);
}

// CHECK-LABEL: @test_ptr_to_global(
// CHECK-NEXT: entry:
Expand Down Expand Up @@ -70,6 +176,72 @@ fixed_int32m1_t array_arg(fixed_int32m1_t arr[]) {
return arr[0];
}

// CHECK-LABEL: @address_of_array_idx_bool1(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca <32 x i8>, align 8
// CHECK-NEXT: [[ARR:%.*]] = alloca [3 x <32 x i8>], align 8
// CHECK-NEXT: [[PARR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [3 x <32 x i8>], ptr [[ARR]], i64 0, i64 0
// CHECK-NEXT: store ptr [[ARRAYIDX]], ptr [[PARR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PARR]], align 8
// CHECK-NEXT: [[TMP1:%.*]] = load <32 x i8>, ptr [[TMP0]], align 8
// CHECK-NEXT: store <32 x i8> [[TMP1]], ptr [[RETVAL]], align 8
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL_COERCE]], ptr align 8 [[RETVAL]], i64 32, i1 false)
// CHECK-NEXT: [[TMP2:%.*]] = load <vscale x 64 x i1>, ptr [[RETVAL_COERCE]], align 8
// CHECK-NEXT: ret <vscale x 64 x i1> [[TMP2]]
//
fixed_bool1_t address_of_array_idx_bool1() {
fixed_bool1_t arr[3];
fixed_bool1_t *parr;
parr = &arr[0];
return *parr;
}

// CHECK-LABEL: @address_of_array_idx_bool4(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca <8 x i8>, align 8
// CHECK-NEXT: [[ARR:%.*]] = alloca [3 x <8 x i8>], align 8
// CHECK-NEXT: [[PARR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [3 x <8 x i8>], ptr [[ARR]], i64 0, i64 0
// CHECK-NEXT: store ptr [[ARRAYIDX]], ptr [[PARR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PARR]], align 8
// CHECK-NEXT: [[TMP1:%.*]] = load <8 x i8>, ptr [[TMP0]], align 8
// CHECK-NEXT: store <8 x i8> [[TMP1]], ptr [[RETVAL]], align 8
// CHECK-NEXT: [[TMP2:%.*]] = load <8 x i8>, ptr [[RETVAL]], align 8
// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call <vscale x 2 x i8> @llvm.vector.insert.nxv2i8.v8i8(<vscale x 2 x i8> undef, <8 x i8> [[TMP2]], i64 0)
// CHECK-NEXT: [[TMP3:%.*]] = bitcast <vscale x 2 x i8> [[CAST_SCALABLE]] to <vscale x 16 x i1>
// CHECK-NEXT: ret <vscale x 16 x i1> [[TMP3]]
//
fixed_bool4_t address_of_array_idx_bool4() {
fixed_bool4_t arr[3];
fixed_bool4_t *parr;
parr = &arr[0];
return *parr;
}

// CHECK-LABEL: @address_of_array_idx_bool32(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca <1 x i8>, align 1
// CHECK-NEXT: [[ARR:%.*]] = alloca [3 x <1 x i8>], align 1
// CHECK-NEXT: [[PARR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca <vscale x 2 x i1>, align 1
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [3 x <1 x i8>], ptr [[ARR]], i64 0, i64 0
// CHECK-NEXT: store ptr [[ARRAYIDX]], ptr [[PARR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PARR]], align 8
// CHECK-NEXT: [[TMP1:%.*]] = load <1 x i8>, ptr [[TMP0]], align 1
// CHECK-NEXT: store <1 x i8> [[TMP1]], ptr [[RETVAL]], align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[RETVAL_COERCE]], ptr align 1 [[RETVAL]], i64 1, i1 false)
// CHECK-NEXT: [[TMP2:%.*]] = load <vscale x 2 x i1>, ptr [[RETVAL_COERCE]], align 1
// CHECK-NEXT: ret <vscale x 2 x i1> [[TMP2]]
//
fixed_bool32_t address_of_array_idx_bool32() {
fixed_bool32_t arr[3];
fixed_bool32_t *parr;
parr = &arr[0];
return *parr;
}

// CHECK-LABEL: @test_cast(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RETVAL:%.*]] = alloca <8 x i32>, align 8
Expand Down
107 changes: 107 additions & 0 deletions clang/test/CodeGen/attr-riscv-rvv-vector-bits-globals.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,25 @@ typedef __rvv_uint64m1_t vuint64m1_t;
typedef __rvv_float32m1_t vfloat32m1_t;
typedef __rvv_float64m1_t vfloat64m1_t;

typedef __rvv_bool1_t vbool1_t;
typedef __rvv_bool4_t vbool4_t;
typedef __rvv_bool32_t vbool32_t;

typedef vint64m1_t fixed_int64m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool1_t fixed_bool1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool4_t fixed_bool4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/4)));
#if __riscv_v_fixed_vlen >= 256
typedef vbool32_t fixed_bool32_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/32)));
#endif

fixed_int64m1_t global_i64;

fixed_bool1_t global_bool1;
fixed_bool4_t global_bool4;
#if __riscv_v_fixed_vlen >= 256
fixed_bool32_t global_bool32;
#endif

//===----------------------------------------------------------------------===//
// WRITES
//===----------------------------------------------------------------------===//
Expand All @@ -39,6 +54,52 @@ fixed_int64m1_t global_i64;
//
void write_global_i64(vint64m1_t v) { global_i64 = v; }

// CHECK-64-LABEL: @write_global_bool1(
// CHECK-64-NEXT: entry:
// CHECK-64-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-64-NEXT: store <vscale x 64 x i1> [[V:%.*]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA7:![0-9]+]]
// CHECK-64-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: store <8 x i8> [[TMP0]], ptr @global_bool1, align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: ret void
//
// CHECK-256-LABEL: @write_global_bool1(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 64 x i1>, align 8
// CHECK-256-NEXT: store <vscale x 64 x i1> [[V:%.*]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA7:![0-9]+]]
// CHECK-256-NEXT: [[TMP0:%.*]] = load <32 x i8>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: store <32 x i8> [[TMP0]], ptr @global_bool1, align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: ret void
//
void write_global_bool1(vbool1_t v) { global_bool1 = v; }

// CHECK-64-LABEL: @write_global_bool4(
// CHECK-64-NEXT: entry:
// CHECK-64-NEXT: [[TMP0:%.*]] = bitcast <vscale x 16 x i1> [[V:%.*]] to <vscale x 2 x i8>
// CHECK-64-NEXT: [[CAST_FIXED:%.*]] = tail call <2 x i8> @llvm.vector.extract.v2i8.nxv2i8(<vscale x 2 x i8> [[TMP0]], i64 0)
// CHECK-64-NEXT: store <2 x i8> [[CAST_FIXED]], ptr @global_bool4, align 2, !tbaa [[TBAA4]]
// CHECK-64-NEXT: ret void
//
// CHECK-256-LABEL: @write_global_bool4(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[TMP0:%.*]] = bitcast <vscale x 16 x i1> [[V:%.*]] to <vscale x 2 x i8>
// CHECK-256-NEXT: [[CAST_FIXED:%.*]] = tail call <8 x i8> @llvm.vector.extract.v8i8.nxv2i8(<vscale x 2 x i8> [[TMP0]], i64 0)
// CHECK-256-NEXT: store <8 x i8> [[CAST_FIXED]], ptr @global_bool4, align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: ret void
//
void write_global_bool4(vbool4_t v) { global_bool4 = v; }

#if __riscv_v_fixed_vlen >= 256
// CHECK-256-LABEL: @write_global_bool32(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[SAVED_VALUE:%.*]] = alloca <vscale x 2 x i1>, align 1
// CHECK-256-NEXT: store <vscale x 2 x i1> [[V:%.*]], ptr [[SAVED_VALUE]], align 1, !tbaa [[TBAA9:![0-9]+]]
// CHECK-256-NEXT: [[TMP0:%.*]] = load <1 x i8>, ptr [[SAVED_VALUE]], align 1, !tbaa [[TBAA4]]
// CHECK-256-NEXT: store <1 x i8> [[TMP0]], ptr @global_bool32, align 1, !tbaa [[TBAA4]]
// CHECK-256-NEXT: ret void
//
void write_global_bool32(vbool32_t v) { global_bool32 = v; }
#endif

//===----------------------------------------------------------------------===//
// READS
//===----------------------------------------------------------------------===//
Expand All @@ -56,3 +117,49 @@ void write_global_i64(vint64m1_t v) { global_i64 = v; }
// CHECK-256-NEXT: ret <vscale x 1 x i64> [[CAST_SCALABLE]]
//
vint64m1_t read_global_i64() { return global_i64; }

// CHECK-64-LABEL: @read_global_bool1(
// CHECK-64-NEXT: entry:
// CHECK-64-NEXT: [[SAVED_VALUE:%.*]] = alloca <8 x i8>, align 8
// CHECK-64-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr @global_bool1, align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: store <8 x i8> [[TMP0]], ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: [[TMP1:%.*]] = load <vscale x 64 x i1>, ptr [[SAVED_VALUE]], align 8, !tbaa [[TBAA4]]
// CHECK-64-NEXT: ret <vscale x 64 x i1> [[TMP1]]
//
// CHECK-256-LABEL: @read_global_bool1(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[SAVED_VALUE:%.*]] = alloca <32 x i8>, align 32
// CHECK-256-NEXT: [[TMP0:%.*]] = load <32 x i8>, ptr @global_bool1, align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: store <32 x i8> [[TMP0]], ptr [[SAVED_VALUE]], align 32, !tbaa [[TBAA4]]
// CHECK-256-NEXT: [[TMP1:%.*]] = load <vscale x 64 x i1>, ptr [[SAVED_VALUE]], align 32, !tbaa [[TBAA4]]
// CHECK-256-NEXT: ret <vscale x 64 x i1> [[TMP1]]
//
vbool1_t read_global_bool1() { return global_bool1; }

// CHECK-64-LABEL: @read_global_bool4(
// CHECK-64-NEXT: entry:
// CHECK-64-NEXT: [[TMP0:%.*]] = load <2 x i8>, ptr @global_bool4, align 2, !tbaa [[TBAA4]]
// CHECK-64-NEXT: [[CAST_SCALABLE:%.*]] = tail call <vscale x 2 x i8> @llvm.vector.insert.nxv2i8.v2i8(<vscale x 2 x i8> undef, <2 x i8> [[TMP0]], i64 0)
// CHECK-64-NEXT: [[TMP1:%.*]] = bitcast <vscale x 2 x i8> [[CAST_SCALABLE]] to <vscale x 16 x i1>
// CHECK-64-NEXT: ret <vscale x 16 x i1> [[TMP1]]
//
// CHECK-256-LABEL: @read_global_bool4(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr @global_bool4, align 8, !tbaa [[TBAA4]]
// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call <vscale x 2 x i8> @llvm.vector.insert.nxv2i8.v8i8(<vscale x 2 x i8> undef, <8 x i8> [[TMP0]], i64 0)
// CHECK-256-NEXT: [[TMP1:%.*]] = bitcast <vscale x 2 x i8> [[CAST_SCALABLE]] to <vscale x 16 x i1>
// CHECK-256-NEXT: ret <vscale x 16 x i1> [[TMP1]]
//
vbool4_t read_global_bool4() { return global_bool4; }

#if __riscv_v_fixed_vlen >= 256
// CHECK-256-LABEL: @read_global_bool32(
// CHECK-256-NEXT: entry:
// CHECK-256-NEXT: [[SAVED_VALUE:%.*]] = alloca <1 x i8>, align 1
// CHECK-256-NEXT: [[TMP0:%.*]] = load <1 x i8>, ptr @global_bool32, align 1, !tbaa [[TBAA4]]
// CHECK-256-NEXT: store <1 x i8> [[TMP0]], ptr [[SAVED_VALUE]], align 1, !tbaa [[TBAA4]]
// CHECK-256-NEXT: [[TMP1:%.*]] = load <vscale x 2 x i1>, ptr [[SAVED_VALUE]], align 1, !tbaa [[TBAA4]]
// CHECK-256-NEXT: ret <vscale x 2 x i1> [[TMP1]]
//
vbool32_t read_global_bool32() { return global_bool32; }
#endif
284 changes: 284 additions & 0 deletions clang/test/CodeGen/attr-riscv-rvv-vector-bits-types.c

Large diffs are not rendered by default.

72 changes: 72 additions & 0 deletions clang/test/CodeGenCXX/riscv-mangle-rvv-fixed-vectors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ typedef __rvv_float16m8_t vfloat16m8_t;
typedef __rvv_float32m8_t vfloat32m8_t;
typedef __rvv_float64m8_t vfloat64m8_t;

typedef __rvv_bool1_t vbool1_t;
typedef __rvv_bool2_t vbool2_t;
typedef __rvv_bool4_t vbool4_t;
typedef __rvv_bool8_t vbool8_t;
typedef __rvv_bool16_t vbool16_t;
typedef __rvv_bool32_t vbool32_t;
typedef __rvv_bool64_t vbool64_t;

typedef vint8mf8_t fixed_int8mf8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/8)));

typedef vuint8mf8_t fixed_uint8mf8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/8)));
Expand Down Expand Up @@ -164,6 +172,20 @@ typedef vfloat16m8_t fixed_float16m8_t __attribute__((riscv_rvv_vector_bits(__ri
typedef vfloat32m8_t fixed_float32m8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen*8)));
typedef vfloat64m8_t fixed_float64m8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen*8)));

typedef vbool1_t fixed_bool1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool2_t fixed_bool2_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/2)));
typedef vbool4_t fixed_bool4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/4)));
typedef vbool8_t fixed_bool8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/8)));
#if __riscv_v_fixed_vlen >= 128
typedef vbool16_t fixed_bool16_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/16)));
#endif
#if __riscv_v_fixed_vlen >= 256
typedef vbool32_t fixed_bool32_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/32)));
#endif
#if __riscv_v_fixed_vlen >= 512
typedef vbool64_t fixed_bool64_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/64)));
#endif

template <typename T> struct S {};

// CHECK-64: _Z2f11SI9__RVV_VLSIu14__rvv_int8m1_tLj64EEE
Expand Down Expand Up @@ -578,3 +600,53 @@ void mf8f1(S<fixed_int8mf8_t>) {}
// CHECK-512: _Z5mf8f51SI9__RVV_VLSIu16__rvv_uint8mf8_tLj64EEE
// CHECK-1024: _Z5mf8f51SI9__RVV_VLSIu16__rvv_uint8mf8_tLj128EEE
void mf8f5(S<fixed_uint8mf8_t>) {}

// CHECK-64: _Z5bool11SI9__RVV_VLSIu13__rvv_bool1_tLj64EEE
// CHECK-128: _Z5bool11SI9__RVV_VLSIu13__rvv_bool1_tLj128EEE
// CHECK-256: _Z5bool11SI9__RVV_VLSIu13__rvv_bool1_tLj256EEE
// CHECK-512: _Z5bool11SI9__RVV_VLSIu13__rvv_bool1_tLj512EEE
// CHECK-1024: _Z5bool11SI9__RVV_VLSIu13__rvv_bool1_tLj1024EEE
void bool1(S<fixed_bool1_t>) {}

// CHECK-64: _Z5bool21SI9__RVV_VLSIu13__rvv_bool2_tLj32EEE
// CHECK-128: _Z5bool21SI9__RVV_VLSIu13__rvv_bool2_tLj64EEE
// CHECK-256: _Z5bool21SI9__RVV_VLSIu13__rvv_bool2_tLj128EEE
// CHECK-512: _Z5bool21SI9__RVV_VLSIu13__rvv_bool2_tLj256EEE
// CHECK-1024: _Z5bool21SI9__RVV_VLSIu13__rvv_bool2_tLj512EEE
void bool2(S<fixed_bool2_t>) {}

// CHECK-64: _Z5bool41SI9__RVV_VLSIu13__rvv_bool4_tLj16EEE
// CHECK-128: _Z5bool41SI9__RVV_VLSIu13__rvv_bool4_tLj32EEE
// CHECK-256: _Z5bool41SI9__RVV_VLSIu13__rvv_bool4_tLj64EEE
// CHECK-512: _Z5bool41SI9__RVV_VLSIu13__rvv_bool4_tLj128EEE
// CHECK-1024: _Z5bool41SI9__RVV_VLSIu13__rvv_bool4_tLj256EEE
void bool4(S<fixed_bool4_t>) {}

// CHECK-64: _Z5bool81SI9__RVV_VLSIu13__rvv_bool8_tLj8EEE
// CHECK-128: _Z5bool81SI9__RVV_VLSIu13__rvv_bool8_tLj16EEE
// CHECK-256: _Z5bool81SI9__RVV_VLSIu13__rvv_bool8_tLj32EEE
// CHECK-512: _Z5bool81SI9__RVV_VLSIu13__rvv_bool8_tLj64EEE
// CHECK-1024: _Z5bool81SI9__RVV_VLSIu13__rvv_bool8_tLj128EEE
void bool8(S<fixed_bool8_t>) {}

#if __riscv_v_fixed_vlen >= 128
// CHECK-128: _Z6bool161SI9__RVV_VLSIu14__rvv_bool16_tLj8EEE
// CHECK-256: _Z6bool161SI9__RVV_VLSIu14__rvv_bool16_tLj16EEE
// CHECK-512: _Z6bool161SI9__RVV_VLSIu14__rvv_bool16_tLj32EEE
// CHECK-1024: _Z6bool161SI9__RVV_VLSIu14__rvv_bool16_tLj64EEE
//
void bool16(S<fixed_bool16_t>) {}
#endif

#if __riscv_v_fixed_vlen >= 256
// CHECK-256: _Z6bool321SI9__RVV_VLSIu14__rvv_bool32_tLj8EEE
// CHECK-512: _Z6bool321SI9__RVV_VLSIu14__rvv_bool32_tLj16EEE
// CHECK-1024: _Z6bool321SI9__RVV_VLSIu14__rvv_bool32_tLj32EEE
void bool32(S<fixed_bool32_t>) {}
#endif

#if __riscv_v_fixed_vlen >= 512
// CHECK-512: _Z6bool641SI9__RVV_VLSIu14__rvv_bool64_tLj8EEE
// CHECK-1024: _Z6bool641SI9__RVV_VLSIu14__rvv_bool64_tLj16EEE
void bool64(S<fixed_bool64_t>) {}
#endif
88 changes: 86 additions & 2 deletions clang/test/Sema/attr-riscv-rvv-vector-bits.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,19 @@ typedef vint8m1_t two_arguments __attribute__((riscv_rvv_vector_bits(2, 4))); //
typedef vint8m1_t non_int_size1 __attribute__((riscv_rvv_vector_bits(2.0))); // expected-error {{'riscv_rvv_vector_bits' attribute requires an integer constant}}
typedef vint8m1_t non_int_size2 __attribute__((riscv_rvv_vector_bits("256"))); // expected-error {{'riscv_rvv_vector_bits' attribute requires an integer constant}}

// bool types and LMUL != 1 are not supported.
typedef vbool1_t fixed_vbool1_t_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); // expected-error {{'riscv_rvv_vector_bits' attribute applied to non-RVV type 'vbool1_t'}}
typedef vbool1_t fixed_bool1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
typedef vbool2_t fixed_bool2_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 2)));
typedef vbool4_t fixed_bool4_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 4)));
typedef vbool8_t fixed_bool8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 8)));
#if __riscv_v_fixed_vlen / 16 >= 8
typedef vbool16_t fixed_bool16_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 16)));
#endif
#if __riscv_v_fixed_vlen / 32 >= 8
typedef vbool32_t fixed_bool32_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 32)));
#endif
#if __riscv_v_fixed_vlen / 64 >= 8
typedef vbool64_t fixed_bool64_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen / 64)));
#endif

// Attribute must be attached to a single RVV vector or predicate type.
typedef void *badtype1 __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); // expected-error {{'riscv_rvv_vector_bits' attribute applied to non-RVV type 'void *'}}
Expand All @@ -242,10 +253,13 @@ vint8m1_t non_typedef_type __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_
// Test that we can define non-local fixed-length RVV types (unsupported for
// sizeless types).
fixed_int8m1_t global_int8;
fixed_bool1_t global_bool1;

extern fixed_int8m1_t extern_int8;
extern fixed_bool1_t extern_bool1;

static fixed_int8m1_t static_int8;
static fixed_bool1_t static_bool1;

fixed_int8m1_t *global_int8_ptr;
extern fixed_int8m1_t *extern_int8_ptr;
Expand Down Expand Up @@ -398,6 +412,20 @@ _Static_assert(sizeof(fixed_int64m8_t) == VECTOR_SIZE * 8, "");
_Static_assert(sizeof(fixed_float32m8_t) == VECTOR_SIZE * 8, "");
_Static_assert(sizeof(fixed_float64m8_t) == VECTOR_SIZE * 8, "");

_Static_assert(sizeof(fixed_bool1_t) == VECTOR_SIZE, "");
_Static_assert(sizeof(fixed_bool2_t) == VECTOR_SIZE / 2, "");
_Static_assert(sizeof(fixed_bool4_t) == VECTOR_SIZE / 4, "");
_Static_assert(sizeof(fixed_bool8_t) == VECTOR_SIZE / 8, "");
#if __riscv_v_fixed_vlen / 16 >= 8
_Static_assert(sizeof(fixed_bool16_t) == VECTOR_SIZE / 16, "");
#endif
#if __riscv_v_fixed_vlen / 32 >= 8
_Static_assert(sizeof(fixed_bool32_t) == VECTOR_SIZE / 32, "");
#endif
#if __riscv_v_fixed_vlen / 64 >= 8
_Static_assert(sizeof(fixed_bool64_t) == VECTOR_SIZE / 64, "");
#endif

// --------------------------------------------------------------------------//
// Alignof

Expand Down Expand Up @@ -475,6 +503,20 @@ _Static_assert(__alignof__(fixed_uint64m8_t) == VECTOR_ALIGN, "");
_Static_assert(__alignof__(fixed_float32m8_t) == VECTOR_ALIGN, "");
_Static_assert(__alignof__(fixed_float64m8_t) == VECTOR_ALIGN, "");

_Static_assert(__alignof__(fixed_bool1_t) == VECTOR_ALIGN, "");
_Static_assert(__alignof__(fixed_bool2_t) == (sizeof(fixed_bool2_t) < VECTOR_ALIGN ? sizeof(fixed_bool2_t) : VECTOR_ALIGN), "");
_Static_assert(__alignof__(fixed_bool4_t) == (sizeof(fixed_bool4_t) < VECTOR_ALIGN ? sizeof(fixed_bool4_t) : VECTOR_ALIGN), "");
_Static_assert(__alignof__(fixed_bool8_t) == (sizeof(fixed_bool8_t) < VECTOR_ALIGN ? sizeof(fixed_bool8_t) : VECTOR_ALIGN), "");
#if __riscv_v_fixed_vlen / 16 >= 8
_Static_assert(__alignof__(fixed_bool16_t) == (sizeof(fixed_bool16_t) < VECTOR_ALIGN ? sizeof(fixed_bool16_t) : VECTOR_ALIGN), "");
#endif
#if __riscv_v_fixed_vlen / 32 >= 8
_Static_assert(__alignof__(fixed_bool32_t) == (sizeof(fixed_bool32_t) < VECTOR_ALIGN ? sizeof(fixed_bool32_t) : VECTOR_ALIGN), "");
#endif
#if __riscv_v_fixed_vlen / 64 >= 8
_Static_assert(__alignof__(fixed_bool64_t) == (sizeof(fixed_bool64_t) < VECTOR_ALIGN ? sizeof(fixed_bool64_t) : VECTOR_ALIGN), "");
#endif

// --------------------------------------------------------------------------//
// Structs

Expand Down Expand Up @@ -580,6 +622,26 @@ TEST_CAST_VECTOR(uint64m8)
TEST_CAST_VECTOR(float32m8)
TEST_CAST_VECTOR(float64m8)

TEST_CAST_COMMON(bool1);
TEST_CAST_COMMON(bool2);
TEST_CAST_COMMON(bool4);
TEST_CAST_COMMON(bool8);
#if __riscv_v_fixed_vlen / 16 >= 8
TEST_CAST_COMMON(bool16);
#endif
#if __riscv_v_fixed_vlen / 32 >= 8
TEST_CAST_COMMON(bool32);
#endif
#if __riscv_v_fixed_vlen / 64 >= 8
TEST_CAST_COMMON(bool64);
#endif

// Test conversion between mask and uint8 is invalid, both have the same
// memory representation.
fixed_bool1_t to_fixed_bool1_t__from_vuint8m1_t(vuint8m1_t x) { return x; } // expected-error-re {{returning 'vuint8m1_t' (aka '__rvv_uint8m1_t') from a function with incompatible result type 'fixed_bool1_t' (vector of {{[0-9]+}} 'unsigned char' values)}}

// --------------------------------------------------------------------------//

// --------------------------------------------------------------------------//
// Test the scalable and fixed-length types can be used interchangeably

Expand All @@ -595,6 +657,14 @@ vfloat64m4_t __attribute__((overloadable)) vfunc(vfloat64m4_t op1, vfloat64m4_t
vint32m8_t __attribute__((overloadable)) vfunc(vint32m8_t op1, vint32m8_t op2);
vfloat64m8_t __attribute__((overloadable)) vfunc(vfloat64m8_t op1, vfloat64m8_t op2);

vbool1_t __attribute__((overloadable)) vfunc(vbool1_t op1, vbool1_t op2);
vbool2_t __attribute__((overloadable)) vfunc(vbool2_t op1, vbool2_t op2);
vbool4_t __attribute__((overloadable)) vfunc(vbool4_t op1, vbool4_t op2);
vbool8_t __attribute__((overloadable)) vfunc(vbool8_t op1, vbool8_t op2);
vbool16_t __attribute__((overloadable)) vfunc(vbool16_t op1, vbool16_t op2);
vbool32_t __attribute__((overloadable)) vfunc(vbool32_t op1, vbool32_t op2);
vbool64_t __attribute__((overloadable)) vfunc(vbool64_t op1, vbool64_t op2);

#define TEST_CALL(TYPE) \
fixed_##TYPE##_t \
call_##TYPE##_ff(fixed_##TYPE##_t op1, fixed_##TYPE##_t op2) { \
Expand All @@ -621,6 +691,20 @@ TEST_CALL(float64m4)
TEST_CALL(int32m8)
TEST_CALL(float64m8)

TEST_CALL(bool1)
TEST_CALL(bool2)
TEST_CALL(bool4)
TEST_CALL(bool8)
#if __riscv_v_fixed_vlen / 16 >= 8
TEST_CALL(bool16)
#endif
#if __riscv_v_fixed_vlen / 32 >= 8
TEST_CALL(bool32)
#endif
#if __riscv_v_fixed_vlen / 64 >= 8
TEST_CALL(bool64)
#endif

// --------------------------------------------------------------------------//
// Vector initialization

Expand Down