From f4d70d68e72d267afab7294918f340e232b94870 Mon Sep 17 00:00:00 2001 From: eopXD Date: Fri, 7 Apr 2023 02:21:44 -0700 Subject: [PATCH] [4/11][POC][Clang][RISCV] Define tuple type variant of vsseg2e32 For the cover letter of this patch-set, please checkout D146872. Depends on D147731. This is the 4th patch of the patch-set. This patch is a proof-of-concept and will be extended to full coverage in the future. Currently, the old non-tuple unit-stride segment store is not removed, and only signed integer unit-strided segment store of NF=2, EEW=32 is defined here. Reviewed By: craig.topper Differential Revision: https://reviews.llvm.org/D147774 --- clang/include/clang/Basic/riscv_vector.td | 50 ++++++++++++++++++++++ clang/lib/CodeGen/CGBuiltin.cpp | 8 ++++ .../non-policy/non-overloaded/vsseg2e32_tuple.c | 31 ++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vsseg2e32_tuple.c diff --git a/clang/include/clang/Basic/riscv_vector.td b/clang/include/clang/Basic/riscv_vector.td index 278b1ce..81f8da8 100644 --- a/clang/include/clang/Basic/riscv_vector.td +++ b/clang/include/clang/Basic/riscv_vector.td @@ -1548,6 +1548,49 @@ multiclass RVVUnitStridedSegLoadTuple { } } } + +multiclass RVVUnitStridedSegStoreTuple { + foreach type = ["i"] in { + defvar eew = !cond(!eq(type, "i") : "32"); + foreach nf = [2] in { + let Name = op # nf # "e" # eew # "_v_tuple", + OverloadedName = op # nf # "e" # eew # "_tuple", + IRName = op # nf, + MaskedIRName = op # nf # "_mask", + NF = nf, + HasMaskedOffOperand = false, + ManualCodegen = [{ + { + // Masked + // Builtin: (mask, ptr, v_tuple, vl) + // Intrinsic: (val0, val1, ..., ptr, mask, vl) + // Unmasked + // Builtin: (ptr, v_tuple, vl) + // Intrinsic: (val0, val1, ..., ptr, vl) + unsigned Offset = IsMasked ? 1 : 0; + llvm::Value *VTupleOperand = Ops[Offset + 1]; + + SmallVector Operands; + for (unsigned I = 0; I < NF; ++I) { + llvm::Value *V = Builder.CreateExtractValue(VTupleOperand, {I}); + Operands.push_back(V); + } + Operands.push_back(Ops[Offset]); // Ptr + if (IsMasked) + Operands.push_back(Ops[0]); + Operands.push_back(Ops[Offset + 2]); // VL + + IntrinsicTypes = {Operands[0]->getType(), Operands.back()->getType()}; + llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); + return Builder.CreateCall(F, Operands, ""); + } + }] in { + defvar T = "(Tuple:" # nf # ")"; + def : RVVBuiltin<"v", "0Pe" # T # "v", type>; + } + } + } +} // TODO: Extend for policy let UnMaskedPolicyScheme = NonePolicy, MaskedPolicyScheme = NonePolicy, @@ -1556,6 +1599,13 @@ defm : RVVUnitStridedSegLoadTuple<"vlseg">; } let UnMaskedPolicyScheme = NonePolicy, + MaskedPolicyScheme = NonePolicy, + IsTuple = true in { +defm : RVVUnitStridedSegStoreTuple<"vsseg">; +} + + +let UnMaskedPolicyScheme = NonePolicy, MaskedPolicyScheme = NonePolicy in { defm : RVVUnitStridedSegStore<"vsseg">; defm : RVVStridedSegStore<"vssseg">; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index b4dae69..736d233 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -19793,6 +19793,14 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, ICEArguments |= (1 << 2); for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) { + // Handle aggregate argument, namely RVV tuple types in segment load/store + if (hasAggregateEvaluationKind(E->getArg(i)->getType())) { + LValue L = EmitAggExprToLValue(E->getArg(i)); + llvm::Value *AggValue = Builder.CreateLoad(L.getAddress(*this)); + Ops.push_back(AggValue); + continue; + } + // If this is a normal argument, just emit it as a scalar. if ((ICEArguments & (1 << i)) == 0) { Ops.push_back(EmitScalarExpr(E->getArg(i))); diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vsseg2e32_tuple.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vsseg2e32_tuple.c new file mode 100644 index 0000000..1f3512e --- /dev/null +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-autogenerated/non-policy/non-overloaded/vsseg2e32_tuple.c @@ -0,0 +1,31 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 +// REQUIRES: riscv-registered-target +// RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh \ +// RUN: -target-feature +experimental-zvfh -disable-O0-optnone \ +// RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ +// RUN: FileCheck --check-prefix=CHECK-RV64 %s +#include + +// CHECK-RV64-LABEL: define dso_local void @test_vsseg2e32_v_tuple_i32m1 +// CHECK-RV64-SAME: (ptr noundef [[BASE:%.*]], [[V_TUPLE_COERCE0:%.*]], [[V_TUPLE_COERCE1:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-RV64-NEXT: entry: +// CHECK-RV64-NEXT: [[TMP0:%.*]] = insertvalue { , } poison, [[V_TUPLE_COERCE0]], 0 +// CHECK-RV64-NEXT: [[TMP1:%.*]] = insertvalue { , } [[TMP0]], [[V_TUPLE_COERCE1]], 1 +// CHECK-RV64-NEXT: [[TMP2:%.*]] = extractvalue { , } [[TMP1]], 0 +// CHECK-RV64-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP1]], 1 +// CHECK-RV64-NEXT: call void @llvm.riscv.vsseg2.nxv2i32.i64( [[TMP2]], [[TMP3]], ptr [[BASE]], i64 [[VL]]) +// CHECK-RV64-NEXT: ret void +// +void test_vsseg2e32_v_tuple_i32m1(int32_t *base, vint32m1x2_t v_tuple, size_t vl) { + return __riscv_vsseg2e32_v_tuple_i32m1(base, v_tuple, vl); +} + +// CHECK-RV64-LABEL: define dso_local void @test_vsseg2e32_v_i32m1_m +// CHECK-RV64-SAME: ( [[MASK:%.*]], ptr noundef [[BASE:%.*]], [[V0:%.*]], [[V1:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] { +// CHECK-RV64-NEXT: entry: +// CHECK-RV64-NEXT: call void @llvm.riscv.vsseg2.mask.nxv2i32.i64( [[V0]], [[V1]], ptr [[BASE]], [[MASK]], i64 [[VL]]) +// CHECK-RV64-NEXT: ret void +// +void test_vsseg2e32_v_i32m1_m(vbool32_t mask, int32_t *base, vint32m1_t v0, vint32m1_t v1, size_t vl) { + return __riscv_vsseg2e32_v_i32m1_m(mask, base, v0, v1, vl); +} -- 2.7.4