Skip to content

[RISCV] Handle zeroinitializer of vector tuple Type #113995

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 4, 2024

Conversation

4vtomat
Copy link
Member

@4vtomat 4vtomat commented Oct 29, 2024

It doesn't make sense to add a new generic ISD to handle riscv tuple
type. Instead we use SPLAT_VECTOR for ISD and further lower to VMV_V_X.

Note: If there's visitSPLAT_VECTOR in generic DAG combiner, it needs
to skip riscv vector tuple type.

Stack on #114329

@llvmbot
Copy link
Member

llvmbot commented Oct 29, 2024

@llvm/pr-subscribers-backend-risc-v

@llvm/pr-subscribers-llvm-selectiondag

Author: Brandon Wu (4vtomat)

Changes

It doesn't make sense to add a new generic ISD to handle riscv tuple
type. Instead we use SPLAT_VECTOR for ISD and further lower to VMV_V_X.

Note: If there's visitSPLAT_VECTOR in generic DAG combiner, it needs
to skip riscv vector tuple type.


Full diff: https://github.com/llvm/llvm-project/pull/113995.diff

5 Files Affected:

  • (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp (+3)
  • (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (+7)
  • (modified) llvm/lib/IR/Type.cpp (+2-1)
  • (modified) llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp (+19)
  • (added) llvm/test/CodeGen/RISCV/vector-tuple-zeroinitializer.ll (+40)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 1a86b3b51234d1..0ba0055f99c094 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6288,6 +6288,9 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
       return getNode(ISD::VECREDUCE_AND, DL, VT, N1);
     break;
   case ISD::SPLAT_VECTOR:
+    // RISC-V vector tuple type is not a vector type.
+    if (VT.isRISCVVectorTuple())
+      break;
     assert(VT.isVector() && "Wrong return type!");
     // FIXME: Hexagon uses i32 scalar for a floating point zero vector so allow
     // that for now.
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 8450553743074c..ca63b289ee20cb 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -1900,6 +1900,13 @@ SDValue SelectionDAGBuilder::getValueImpl(const Value *V) {
                          DAG.getConstant(0, getCurSDLoc(), MVT::nxv16i1));
     }
 
+    if (VT.isRISCVVectorTuple()) {
+      assert(C->isNullValue() && "Can only zero this target type!");
+      return NodeMap[V] = DAG.getNode(
+                 ISD::SPLAT_VECTOR, getCurSDLoc(), VT,
+                 DAG.getConstant(0, getCurSDLoc(), MVT::getIntegerVT(8)));
+    }
+
     VectorType *VecTy = cast<VectorType>(V->getType());
 
     // Now that we know the number and type of the elements, get that number of
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index e311cde415174a..e5fe85dbd18e39 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -880,7 +880,8 @@ static TargetTypeInfo getTargetTypeInfo(const TargetExtType *Ty) {
                  RISCV::RVVBitsPerBlock / 8) *
         Ty->getIntParameter(0);
     return TargetTypeInfo(
-        ScalableVectorType::get(Type::getInt8Ty(C), TotalNumElts));
+        ScalableVectorType::get(Type::getInt8Ty(C), TotalNumElts),
+        TargetExtType::HasZeroInit);
   }
 
   // DirectX resources
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index dc3f8254cb4e00..998f1e2188ff0b 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -66,6 +66,25 @@ void RISCVDAGToDAGISel::PreprocessISelDAG() {
           VT.isInteger() ? RISCVISD::VMV_V_X_VL : RISCVISD::VFMV_V_F_VL;
       SDLoc DL(N);
       SDValue VL = CurDAG->getRegister(RISCV::X0, Subtarget->getXLenVT());
+
+      if (VT.isRISCVVectorTuple()) {
+        unsigned NF = VT.getRISCVVectorTupleNumFields();
+        unsigned NumScalElts = VT.getSizeInBits() / (NF * 8);
+        SDValue EltVal = CurDAG->getConstant(0, DL, Subtarget->getXLenVT());
+        MVT ScalTy =
+            MVT::getScalableVectorVT(MVT::getIntegerVT(8), NumScalElts);
+
+        SDValue Splat = CurDAG->getNode(RISCVISD::VMV_V_X_VL, DL, ScalTy,
+                                        CurDAG->getUNDEF(ScalTy), EltVal, VL);
+
+        Result = CurDAG->getUNDEF(VT);
+        for (unsigned i = 0; i < NF; ++i)
+          Result = CurDAG->getNode(RISCVISD::TUPLE_INSERT, DL, VT, Result,
+                                   Splat, CurDAG->getVectorIdxConstant(i, DL));
+
+        break;
+      }
+
       SDValue Src = N->getOperand(0);
       if (VT.isInteger())
         Src = CurDAG->getNode(ISD::ANY_EXTEND, DL, Subtarget->getXLenVT(),
diff --git a/llvm/test/CodeGen/RISCV/vector-tuple-zeroinitializer.ll b/llvm/test/CodeGen/RISCV/vector-tuple-zeroinitializer.ll
new file mode 100644
index 00000000000000..88e1315d560b07
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/vector-tuple-zeroinitializer.ll
@@ -0,0 +1,40 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+v \
+; RUN:   -verify-machineinstrs | FileCheck %s --check-prefixes=CHECK
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+v \
+; RUN:   -verify-machineinstrs | FileCheck %s --check-prefixes=CHECK
+
+define target("riscv.vector.tuple", <vscale x 16 x i8>, 2) @test_tuple_zero0() {
+; CHECK-LABEL: test_tuple_zero0:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vsetvli a0, zero, e8, m2, ta, ma
+; CHECK-NEXT:    vmv.v.i v8, 0
+; CHECK-NEXT:    vmv.v.i v10, 0
+; CHECK-NEXT:    ret
+entry:
+  ret target("riscv.vector.tuple", <vscale x 16 x i8>, 2) zeroinitializer
+}
+
+define target("riscv.vector.tuple", <vscale x 16 x i8>, 2) @test_tuple_zero1(<vscale x 4 x i32> %a) {
+; CHECK-LABEL: test_tuple_zero1:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vsetvli a0, zero, e8, m2, ta, ma
+; CHECK-NEXT:    vmv.v.i v10, 0
+; CHECK-NEXT:    ret
+entry:
+  %1 = call target("riscv.vector.tuple", <vscale x 16 x i8>, 2) @llvm.riscv.tuple.insert.triscv.vector.tuple_nxv16i8_2t.nxv4i32(target("riscv.vector.tuple", <vscale x 16 x i8>, 2) zeroinitializer, <vscale x 4 x i32> %a, i32 0)
+  ret target("riscv.vector.tuple", <vscale x 16 x i8>, 2) %1
+}
+
+define target("riscv.vector.tuple", <vscale x 16 x i8>, 2) @test_tuple_zero2(<vscale x 4 x i32> %a) {
+; CHECK-LABEL: test_tuple_zero2:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vsetvli a0, zero, e8, m2, ta, ma
+; CHECK-NEXT:    vmv.v.i v6, 0
+; CHECK-NEXT:    vmv2r.v v10, v8
+; CHECK-NEXT:    vmv2r.v v8, v6
+; CHECK-NEXT:    ret
+entry:
+  %1 = call target("riscv.vector.tuple", <vscale x 16 x i8>, 2) @llvm.riscv.tuple.insert.triscv.vector.tuple_nxv16i8_2t.nxv4i32(target("riscv.vector.tuple", <vscale x 16 x i8>, 2) zeroinitializer, <vscale x 4 x i32> %a, i32 1)
+  ret target("riscv.vector.tuple", <vscale x 16 x i8>, 2) %1
+}

@llvmbot
Copy link
Member

llvmbot commented Oct 29, 2024

@llvm/pr-subscribers-llvm-ir

Author: Brandon Wu (4vtomat)

Changes

It doesn't make sense to add a new generic ISD to handle riscv tuple
type. Instead we use SPLAT_VECTOR for ISD and further lower to VMV_V_X.

Note: If there's visitSPLAT_VECTOR in generic DAG combiner, it needs
to skip riscv vector tuple type.


Full diff: https://github.com/llvm/llvm-project/pull/113995.diff

5 Files Affected:

  • (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp (+3)
  • (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (+7)
  • (modified) llvm/lib/IR/Type.cpp (+2-1)
  • (modified) llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp (+19)
  • (added) llvm/test/CodeGen/RISCV/vector-tuple-zeroinitializer.ll (+40)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 1a86b3b51234d1..0ba0055f99c094 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6288,6 +6288,9 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
       return getNode(ISD::VECREDUCE_AND, DL, VT, N1);
     break;
   case ISD::SPLAT_VECTOR:
+    // RISC-V vector tuple type is not a vector type.
+    if (VT.isRISCVVectorTuple())
+      break;
     assert(VT.isVector() && "Wrong return type!");
     // FIXME: Hexagon uses i32 scalar for a floating point zero vector so allow
     // that for now.
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 8450553743074c..ca63b289ee20cb 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -1900,6 +1900,13 @@ SDValue SelectionDAGBuilder::getValueImpl(const Value *V) {
                          DAG.getConstant(0, getCurSDLoc(), MVT::nxv16i1));
     }
 
+    if (VT.isRISCVVectorTuple()) {
+      assert(C->isNullValue() && "Can only zero this target type!");
+      return NodeMap[V] = DAG.getNode(
+                 ISD::SPLAT_VECTOR, getCurSDLoc(), VT,
+                 DAG.getConstant(0, getCurSDLoc(), MVT::getIntegerVT(8)));
+    }
+
     VectorType *VecTy = cast<VectorType>(V->getType());
 
     // Now that we know the number and type of the elements, get that number of
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index e311cde415174a..e5fe85dbd18e39 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -880,7 +880,8 @@ static TargetTypeInfo getTargetTypeInfo(const TargetExtType *Ty) {
                  RISCV::RVVBitsPerBlock / 8) *
         Ty->getIntParameter(0);
     return TargetTypeInfo(
-        ScalableVectorType::get(Type::getInt8Ty(C), TotalNumElts));
+        ScalableVectorType::get(Type::getInt8Ty(C), TotalNumElts),
+        TargetExtType::HasZeroInit);
   }
 
   // DirectX resources
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index dc3f8254cb4e00..998f1e2188ff0b 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -66,6 +66,25 @@ void RISCVDAGToDAGISel::PreprocessISelDAG() {
           VT.isInteger() ? RISCVISD::VMV_V_X_VL : RISCVISD::VFMV_V_F_VL;
       SDLoc DL(N);
       SDValue VL = CurDAG->getRegister(RISCV::X0, Subtarget->getXLenVT());
+
+      if (VT.isRISCVVectorTuple()) {
+        unsigned NF = VT.getRISCVVectorTupleNumFields();
+        unsigned NumScalElts = VT.getSizeInBits() / (NF * 8);
+        SDValue EltVal = CurDAG->getConstant(0, DL, Subtarget->getXLenVT());
+        MVT ScalTy =
+            MVT::getScalableVectorVT(MVT::getIntegerVT(8), NumScalElts);
+
+        SDValue Splat = CurDAG->getNode(RISCVISD::VMV_V_X_VL, DL, ScalTy,
+                                        CurDAG->getUNDEF(ScalTy), EltVal, VL);
+
+        Result = CurDAG->getUNDEF(VT);
+        for (unsigned i = 0; i < NF; ++i)
+          Result = CurDAG->getNode(RISCVISD::TUPLE_INSERT, DL, VT, Result,
+                                   Splat, CurDAG->getVectorIdxConstant(i, DL));
+
+        break;
+      }
+
       SDValue Src = N->getOperand(0);
       if (VT.isInteger())
         Src = CurDAG->getNode(ISD::ANY_EXTEND, DL, Subtarget->getXLenVT(),
diff --git a/llvm/test/CodeGen/RISCV/vector-tuple-zeroinitializer.ll b/llvm/test/CodeGen/RISCV/vector-tuple-zeroinitializer.ll
new file mode 100644
index 00000000000000..88e1315d560b07
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/vector-tuple-zeroinitializer.ll
@@ -0,0 +1,40 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+v \
+; RUN:   -verify-machineinstrs | FileCheck %s --check-prefixes=CHECK
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+v \
+; RUN:   -verify-machineinstrs | FileCheck %s --check-prefixes=CHECK
+
+define target("riscv.vector.tuple", <vscale x 16 x i8>, 2) @test_tuple_zero0() {
+; CHECK-LABEL: test_tuple_zero0:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vsetvli a0, zero, e8, m2, ta, ma
+; CHECK-NEXT:    vmv.v.i v8, 0
+; CHECK-NEXT:    vmv.v.i v10, 0
+; CHECK-NEXT:    ret
+entry:
+  ret target("riscv.vector.tuple", <vscale x 16 x i8>, 2) zeroinitializer
+}
+
+define target("riscv.vector.tuple", <vscale x 16 x i8>, 2) @test_tuple_zero1(<vscale x 4 x i32> %a) {
+; CHECK-LABEL: test_tuple_zero1:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vsetvli a0, zero, e8, m2, ta, ma
+; CHECK-NEXT:    vmv.v.i v10, 0
+; CHECK-NEXT:    ret
+entry:
+  %1 = call target("riscv.vector.tuple", <vscale x 16 x i8>, 2) @llvm.riscv.tuple.insert.triscv.vector.tuple_nxv16i8_2t.nxv4i32(target("riscv.vector.tuple", <vscale x 16 x i8>, 2) zeroinitializer, <vscale x 4 x i32> %a, i32 0)
+  ret target("riscv.vector.tuple", <vscale x 16 x i8>, 2) %1
+}
+
+define target("riscv.vector.tuple", <vscale x 16 x i8>, 2) @test_tuple_zero2(<vscale x 4 x i32> %a) {
+; CHECK-LABEL: test_tuple_zero2:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vsetvli a0, zero, e8, m2, ta, ma
+; CHECK-NEXT:    vmv.v.i v6, 0
+; CHECK-NEXT:    vmv2r.v v10, v8
+; CHECK-NEXT:    vmv2r.v v8, v6
+; CHECK-NEXT:    ret
+entry:
+  %1 = call target("riscv.vector.tuple", <vscale x 16 x i8>, 2) @llvm.riscv.tuple.insert.triscv.vector.tuple_nxv16i8_2t.nxv4i32(target("riscv.vector.tuple", <vscale x 16 x i8>, 2) zeroinitializer, <vscale x 4 x i32> %a, i32 1)
+  ret target("riscv.vector.tuple", <vscale x 16 x i8>, 2) %1
+}

Copy link
Contributor

@wangpc-pp wangpc-pp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we should add TargetExtType::HasZeroInit attribute to riscv.vector.tuple type in llvm/lib/IR/Type.cpp:getTargetTypeInfo?

@4vtomat
Copy link
Member Author

4vtomat commented Oct 29, 2024

Then we should add TargetExtType::HasZeroInit attribute to riscv.vector.tuple type in llvm/lib/IR/Type.cpp:getTargetTypeInfo?

Yeah, I think I added? Or do you mean we shouldn't add?

@wangpc-pp
Copy link
Contributor

Then we should add TargetExtType::HasZeroInit attribute to riscv.vector.tuple type in llvm/lib/IR/Type.cpp:getTargetTypeInfo?

Yeah, I think I added? Or do you mean we shouldn't add?

Oh, never mind! Somehow the changes in Type.cpp escaped my eyes. :-)

@preames
Copy link
Collaborator

preames commented Oct 29, 2024

I'm clearly missing some context here, but... why do we need anything specific here to RISCVTupleType at all? At the IR level, why is this not simply a struct? I'd have assumed we already had the lowering for a first class aggregate, what am I missing here?

@topperc
Copy link
Collaborator

topperc commented Oct 30, 2024

I'm clearly missing some context here, but... why do we need anything specific here to RISCVTupleType at all? At the IR level, why is this not simply a struct? I'd have assumed we already had the lowering for a first class aggregate, what am I missing here?

It was a struct a couple months ago. Unfortunately, SelectionDAGBuilder decomposes structs into individual fields before call/return handling and before inline assembly handling. This made it very difficult to have an ABI for tuples or handle tuple operands in inline assembly.

See #97992 and #97993 and #97994 and #97995

@preames
Copy link
Collaborator

preames commented Oct 30, 2024

I'm clearly missing some context here, but... why do we need anything specific here to RISCVTupleType at all? At the IR level, why is this not simply a struct? I'd have assumed we already had the lowering for a first class aggregate, what am I missing here?

It was a struct a couple months ago. Unfortunately, SelectionDAGBuilder decomposes structs into individual fields before call/return handling and before inline assembly handling. This made it very difficult to have an ABI for tuples or handle tuple operands in inline assembly.

See #97992 and #97993 and #97994 and #97995

That was the context I was missing, thanks.

@4vtomat 4vtomat force-pushed the riscv_tuple_zero_initializer branch from 87dd7c3 to dbe42eb Compare November 19, 2024 07:48
@4vtomat
Copy link
Member Author

4vtomat commented Nov 19, 2024

I added a ISD::BITCAST case in PreprocessISelDAG, but somehow the git diff made it looks like I also changed the code in ISD::SPLAT_VECTOR case where I didn't lol

@4vtomat 4vtomat force-pushed the riscv_tuple_zero_initializer branch from dbe42eb to 663cd55 Compare November 19, 2024 12:30
It doesn't make sense to add a new generic ISD to handle riscv tuple
type. Instead we use `SPLAT_VECTOR` for ISD and further lower to `VMV_V_X`.

Note: If there's `visitSPLAT_VECTOR` in generic DAG combiner, it needs
to skip riscv vector tuple type.
@4vtomat 4vtomat force-pushed the riscv_tuple_zero_initializer branch from 3fc09d4 to 5ffa3cb Compare November 26, 2024 06:36
Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@4vtomat 4vtomat merged commit 109e4a1 into llvm:main Dec 4, 2024
8 checks passed
@4vtomat 4vtomat deleted the riscv_tuple_zero_initializer branch December 4, 2024 05:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants