Skip to content

Commit 034cc2f

Browse files
[GISEL] Add G_INSERT_SUBVECTOR and G_EXTRACT_SUBVECTOR (#84538)
G_INSERT and G_EXTRACT are not sufficient to use to represent both INSERT/EXTRACT on a subregister and INSERT/EXTRACT on a vector. We would like to be able to INSERT/EXTRACT on vectors in cases that INSERT/EXTRACT on vector subregisters are not sufficient, so we add these opcodes. I tried to do a patch where we treated G_EXTRACT as both G_EXTRACT_SUBVECTOR and G_EXTRACT_SUBREG, but ran into an infinite loop at this [point](https://github.com/llvm/llvm-project/blob/8b5b294ec2cf876bc5eb5bd5fcb56ef487e36d60/llvm/lib/Target/RISCV/RISCVISelLowering.cpp#L9932) in the SDAG equivalent code.
1 parent 8467457 commit 034cc2f

File tree

9 files changed

+267
-0
lines changed

9 files changed

+267
-0
lines changed

llvm/docs/GlobalISel/GenericOpcode.rst

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,41 @@ See the LLVM LangRef entry on '``llvm.lround.*'`` for details on behaviour.
607607
Vector Specific Operations
608608
--------------------------
609609

610+
G_INSERT_SUBVECTOR
611+
^^^^^^^^^^^^^^^^^^
612+
613+
Insert the second source vector into the first source vector. The index operand
614+
represents the starting index in the first source vector at which the second
615+
source vector should be inserted into.
616+
617+
The index must be a constant multiple of the second source vector's minimum
618+
vector length. If the vectors are scalable, then the index is first scaled by
619+
the runtime scaling factor. The indices inserted in the source vector must be
620+
valid indicies of that vector. If this condition cannot be determined statically
621+
but is false at runtime, then the result vector is undefined.
622+
623+
.. code-block:: none
624+
625+
%2:_(<vscale x 4 x i64>) = G_INSERT_SUBVECTOR %0:_(<vscale x 4 x i64>), %1:_(<vscale x 2 x i64>), 0
626+
627+
G_EXTRACT_SUBVECTOR
628+
^^^^^^^^^^^^^^^^^^^
629+
630+
Extract a vector of destination type from the source vector. The index operand
631+
represents the starting index from which a subvector is extracted from
632+
the source vector.
633+
634+
The index must be a constant multiple of the source vector's minimum vector
635+
length. If the source vector is a scalable vector, then the index is first
636+
scaled by the runtime scaling factor. The indices extracted from the source
637+
vector must be valid indicies of that vector. If this condition cannot be
638+
determined statically but is false at runtime, then the result vector is
639+
undefined.
640+
641+
.. code-block:: none
642+
643+
%3:_(<vscale x 4 x i64>) = G_EXTRACT_SUBVECTOR %2:_(<vscale x 8 x i64>), 2
644+
610645
G_CONCAT_VECTORS
611646
^^^^^^^^^^^^^^^^
612647

llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,25 @@ class MachineIRBuilder {
11211121
MachineInstrBuilder buildConcatVectors(const DstOp &Res,
11221122
ArrayRef<Register> Ops);
11231123

1124+
/// Build and insert `Res = G_INSERT_SUBVECTOR Src0, Src1, Idx`.
1125+
///
1126+
/// \pre setBasicBlock or setMI must have been called.
1127+
/// \pre \p Res, \p Src0, and \p Src1 must be generic virtual registers with
1128+
/// vector type.
1129+
///
1130+
/// \return a MachineInstrBuilder for the newly created instruction.
1131+
MachineInstrBuilder buildInsertSubvector(const DstOp &Res, const SrcOp &Src0,
1132+
const SrcOp &Src1, unsigned Index);
1133+
1134+
/// Build and insert `Res = G_EXTRACT_SUBVECTOR Src, Idx0`.
1135+
///
1136+
/// \pre setBasicBlock or setMI must have been called.
1137+
/// \pre \p Res and \p Src must be generic virtual registers with vector type.
1138+
///
1139+
/// \return a MachineInstrBuilder for the newly created instruction.
1140+
MachineInstrBuilder buildExtractSubvector(const DstOp &Res, const SrcOp &Src,
1141+
unsigned Index);
1142+
11241143
MachineInstrBuilder buildInsert(const DstOp &Res, const SrcOp &Src,
11251144
const SrcOp &Op, unsigned Index);
11261145

llvm/include/llvm/Support/TargetOpcodes.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,12 @@ HANDLE_TARGET_OPCODE(G_BR)
727727
/// Generic branch to jump table entry.
728728
HANDLE_TARGET_OPCODE(G_BRJT)
729729

730+
/// Generic insert subvector.
731+
HANDLE_TARGET_OPCODE(G_INSERT_SUBVECTOR)
732+
733+
/// Generic extract subvector.
734+
HANDLE_TARGET_OPCODE(G_EXTRACT_SUBVECTOR)
735+
730736
/// Generic insertelement.
731737
HANDLE_TARGET_OPCODE(G_INSERT_VECTOR_ELT)
732738

llvm/include/llvm/Target/GenericOpcodes.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1426,6 +1426,20 @@ def G_WRITE_REGISTER : GenericInstruction {
14261426
// Vector ops
14271427
//------------------------------------------------------------------------------
14281428

1429+
// Generic insert subvector.
1430+
def G_INSERT_SUBVECTOR : GenericInstruction {
1431+
let OutOperandList = (outs type0:$dst);
1432+
let InOperandList = (ins type0:$src0, type1:$src1, untyped_imm_0:$idx);
1433+
let hasSideEffects = false;
1434+
}
1435+
1436+
// Generic extract subvector.
1437+
def G_EXTRACT_SUBVECTOR : GenericInstruction {
1438+
let OutOperandList = (outs type0:$dst);
1439+
let InOperandList = (ins type0:$src, untyped_imm_0:$idx);
1440+
let hasSideEffects = false;
1441+
}
1442+
14291443
// Generic insertelement.
14301444
def G_INSERT_VECTOR_ELT : GenericInstruction {
14311445
let OutOperandList = (outs type0:$dst);

llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,21 @@ MachineIRBuilder::buildSelect(const DstOp &Res, const SrcOp &Tst,
877877
return buildInstr(TargetOpcode::G_SELECT, {Res}, {Tst, Op0, Op1}, Flags);
878878
}
879879

880+
MachineInstrBuilder MachineIRBuilder::buildInsertSubvector(const DstOp &Res,
881+
const SrcOp &Src0,
882+
const SrcOp &Src1,
883+
unsigned Idx) {
884+
return buildInstr(TargetOpcode::G_INSERT_SUBVECTOR, Res,
885+
{Src0, Src1, uint64_t(Idx)});
886+
}
887+
888+
MachineInstrBuilder MachineIRBuilder::buildExtractSubvector(const DstOp &Res,
889+
const SrcOp &Src,
890+
unsigned Idx) {
891+
return buildInstr(TargetOpcode::G_INSERT_SUBVECTOR, Res,
892+
{Src, uint64_t(Idx)});
893+
}
894+
880895
MachineInstrBuilder
881896
MachineIRBuilder::buildInsertVectorElement(const DstOp &Res, const SrcOp &Val,
882897
const SrcOp &Elt, const SrcOp &Idx) {

llvm/lib/CodeGen/MachineVerifier.cpp

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,6 +1613,104 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
16131613
report("G_BSWAP size must be a multiple of 16 bits", MI);
16141614
break;
16151615
}
1616+
case TargetOpcode::G_INSERT_SUBVECTOR: {
1617+
const MachineOperand &Src0Op = MI->getOperand(1);
1618+
if (!Src0Op.isReg()) {
1619+
report("G_INSERT_SUBVECTOR first source must be a register", MI);
1620+
break;
1621+
}
1622+
1623+
const MachineOperand &Src1Op = MI->getOperand(2);
1624+
if (!Src1Op.isReg()) {
1625+
report("G_INSERT_SUBVECTOR second source must be a register", MI);
1626+
break;
1627+
}
1628+
1629+
const MachineOperand &IndexOp = MI->getOperand(3);
1630+
if (!IndexOp.isImm()) {
1631+
report("G_INSERT_SUBVECTOR index must be an immediate", MI);
1632+
break;
1633+
}
1634+
1635+
LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
1636+
LLT Src0Ty = MRI->getType(Src0Op.getReg());
1637+
LLT Src1Ty = MRI->getType(Src1Op.getReg());
1638+
1639+
if (!DstTy.isVector()) {
1640+
report("Destination type must be a vector", MI);
1641+
break;
1642+
}
1643+
1644+
if (!Src0Ty.isVector()) {
1645+
report("First source must be a vector", MI);
1646+
break;
1647+
}
1648+
1649+
if (!Src1Ty.isVector()) {
1650+
report("Second source must be a vector", MI);
1651+
break;
1652+
}
1653+
1654+
if (DstTy != Src0Ty) {
1655+
report("Destination type must match the first source vector type", MI);
1656+
break;
1657+
}
1658+
1659+
if (Src0Ty.getElementType() != Src1Ty.getElementType()) {
1660+
report("Element type of source vectors must be the same", MI);
1661+
break;
1662+
}
1663+
1664+
if (IndexOp.getImm() != 0 &&
1665+
Src1Ty.getElementCount().getKnownMinValue() % IndexOp.getImm() != 0) {
1666+
report("Index must be a multiple of the second source vector's "
1667+
"minimum vector length",
1668+
MI);
1669+
break;
1670+
}
1671+
break;
1672+
}
1673+
case TargetOpcode::G_EXTRACT_SUBVECTOR: {
1674+
const MachineOperand &SrcOp = MI->getOperand(1);
1675+
if (!SrcOp.isReg()) {
1676+
report("G_EXTRACT_SUBVECTOR first source must be a register", MI);
1677+
break;
1678+
}
1679+
1680+
const MachineOperand &IndexOp = MI->getOperand(2);
1681+
if (!IndexOp.isImm()) {
1682+
report("G_EXTRACT_SUBVECTOR index must be an immediate", MI);
1683+
break;
1684+
}
1685+
1686+
LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
1687+
LLT SrcTy = MRI->getType(SrcOp.getReg());
1688+
1689+
if (!DstTy.isVector()) {
1690+
report("Destination type must be a vector", MI);
1691+
break;
1692+
}
1693+
1694+
if (!SrcTy.isVector()) {
1695+
report("First source must be a vector", MI);
1696+
break;
1697+
}
1698+
1699+
if (DstTy.getElementType() != SrcTy.getElementType()) {
1700+
report("Element type of vectors must be the same", MI);
1701+
break;
1702+
}
1703+
1704+
if (IndexOp.getImm() != 0 &&
1705+
SrcTy.getElementCount().getKnownMinValue() % IndexOp.getImm() != 0) {
1706+
report("Index must be a multiple of the source vector's minimum vector "
1707+
"length",
1708+
MI);
1709+
break;
1710+
}
1711+
1712+
break;
1713+
}
16161714
case TargetOpcode::G_SHUFFLE_VECTOR: {
16171715
const MachineOperand &MaskOp = MI->getOperand(3);
16181716
if (!MaskOp.isShuffleMask()) {

llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,12 @@
616616
# DEBUG-NEXT: G_BRJT (opcode {{[0-9]+}}): 2 type indices
617617
# DEBUG-NEXT: .. the first uncovered type index: 2, OK
618618
# DEBUG-NEXT: .. the first uncovered imm index: 0, OK
619+
# DEBUG-NEXT: G_INSERT_SUBVECTOR (opcode {{[0-9]+}}): 2 type indices, 1 imm index
620+
# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
621+
# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
622+
# DEBUG-NEXT: G_EXTRACT_SUBVECTOR (opcode {{[0-9]+}}): 1 type index, 1 imm index
623+
# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
624+
# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
619625
# DEBUG-NEXT: G_INSERT_VECTOR_ELT (opcode {{[0-9]+}}): 3 type indices, 0 imm indices
620626
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
621627
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# RUN: not --crash llc -o - -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s
2+
---
3+
name: g_extract_subvector
4+
tracksRegLiveness: true
5+
liveins:
6+
body: |
7+
bb.0:
8+
%0:_(s32) = G_CONSTANT i32 0
9+
%1:_(<vscale x 2 x s32>) = G_IMPLICIT_DEF
10+
%2:_(<vscale x 1 x s32>) = G_IMPLICIT_DEF
11+
12+
; CHECK: G_EXTRACT_SUBVECTOR first source must be a register
13+
%3:_(<vscale x 2 x s32>) = G_EXTRACT_SUBVECTOR 1, 0
14+
15+
; CHECK: G_EXTRACT_SUBVECTOR index must be an immediate
16+
%4:_(<vscale x 1 x s32>) = G_EXTRACT_SUBVECTOR %2, %0
17+
18+
; CHECK: Destination type must be a vector
19+
%5:_(s32) = G_EXTRACT_SUBVECTOR %2, 0
20+
21+
; CHECK: First source must be a vector
22+
%6:_(<vscale x 2 x s32>) = G_EXTRACT_SUBVECTOR %0, 0
23+
24+
%7:_(<vscale x 1 x s16>) = G_IMPLICIT_DEF
25+
26+
; CHECK: Element type of vectors must be the same
27+
%8:_(<vscale x 2 x s32>) = G_EXTRACT_SUBVECTOR %7, 0
28+
29+
; CHECK: Index must be a multiple of the source vector's minimum vector length
30+
%9:_(<vscale x 4 x s32>) = G_EXTRACT_SUBVECTOR %1, 3
31+
...
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# RUN: not --crash llc -o - -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s
2+
3+
---
4+
name: g_splat_vector
5+
tracksRegLiveness: true
6+
liveins:
7+
body: |
8+
bb.0:
9+
%0:_(s32) = G_CONSTANT i32 0
10+
%1:_(<vscale x 2 x s32>) = G_IMPLICIT_DEF
11+
%2:_(<vscale x 1 x s32>) = G_IMPLICIT_DEF
12+
13+
; CHECK: G_INSERT_SUBVECTOR first source must be a register
14+
%3:_(<vscale x 2 x s32>) = G_INSERT_SUBVECTOR 1, %2, 0
15+
16+
; CHECK: G_INSERT_SUBVECTOR second source must be a register
17+
%4:_(<vscale x 2 x s32>) = G_INSERT_SUBVECTOR %1, 1, 0
18+
19+
; CHECK: G_INSERT_SUBVECTOR index must be an immediate
20+
%5:_(<vscale x 2 x s32>) = G_INSERT_SUBVECTOR %1, %2, %0
21+
22+
; CHECK: Destination type must be a vector
23+
%6:_(s32) = G_INSERT_SUBVECTOR %1, %2, 0
24+
25+
; CHECK: First source must be a vector
26+
%7:_(<vscale x 2 x s32>) = G_INSERT_SUBVECTOR %0, %2, 0
27+
28+
; CHECK: Second source must be a vector
29+
%8:_(<vscale x 2 x s32>) = G_INSERT_SUBVECTOR %1, %0, 0
30+
31+
; CHECK: Destination type must match the first source vector type
32+
%9:_(<vscale x 2 x s32>) = G_INSERT_SUBVECTOR %2, %1, 0
33+
34+
%10:_(<vscale x 1 x s16>) = G_IMPLICIT_DEF
35+
36+
; CHECK: Element type of source vectors must be the same
37+
%11:_(<vscale x 2 x s32>) = G_INSERT_SUBVECTOR %1, %10, 0
38+
39+
%12:_(<vscale x 4 x s32>) = G_IMPLICIT_DEF
40+
41+
; CHECK: Index must be a multiple of the second source vector's minimum vector length
42+
%13:_(<vscale x 4 x s32>) = G_INSERT_SUBVECTOR %12, %1, 3
43+
...

0 commit comments

Comments
 (0)