Skip to content

[GISEL] Add G_INSERT_SUBVECTOR and G_EXTRACT_SUBVECTOR #84538

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 2 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions llvm/docs/GlobalISel/GenericOpcode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,41 @@ See the LLVM LangRef entry on '``llvm.lround.*'`` for details on behaviour.
Vector Specific Operations
--------------------------

G_INSERT_SUBVECTOR
^^^^^^^^^^^^^^^^^^

Insert the second source vector into the first source vector. The index operand
represents the starting index in the first source vector at which the second
source vector should be inserted into.

The index must be a constant multiple of the second source vector's minimum
vector length. If the vectors are scalable, then the index is first scaled by
the runtime scaling factor. The indices inserted in the source vector must be
valid indicies of that vector. If this condition cannot be determined statically
but is false at runtime, then the result vector is undefined.

.. code-block:: none
%2:_(<vscale x 4 x i64>) = G_INSERT_SUBVECTOR %0:_(<vscale x 4 x i64>), %1:_(<vscale x 2 x i64>), 0
G_EXTRACT_SUBVECTOR
^^^^^^^^^^^^^^^^^^^

Extract a vector of destination type from the source vector. The index operand
represents the starting index from which a subvector is extracted from
the source vector.

The index must be a constant multiple of the source vector's minimum vector
length. If the source vector is a scalable vector, then the index is first
scaled by the runtime scaling factor. The indices extracted from the source
vector must be valid indicies of that vector. If this condition cannot be
determined statically but is false at runtime, then the result vector is
undefined.

.. code-block:: none
%3:_(<vscale x 4 x i64>) = G_EXTRACT_SUBVECTOR %2:_(<vscale x 8 x i64>), 2
G_CONCAT_VECTORS
^^^^^^^^^^^^^^^^

Expand Down
19 changes: 19 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,25 @@ class MachineIRBuilder {
MachineInstrBuilder buildConcatVectors(const DstOp &Res,
ArrayRef<Register> Ops);

/// Build and insert `Res = G_INSERT_SUBVECTOR Src0, Src1, Idx`.
///
/// \pre setBasicBlock or setMI must have been called.
/// \pre \p Res, \p Src0, and \p Src1 must be generic virtual registers with
/// vector type.
///
/// \return a MachineInstrBuilder for the newly created instruction.
MachineInstrBuilder buildInsertSubvector(const DstOp &Res, const SrcOp &Src0,
const SrcOp &Src1, unsigned Index);

/// Build and insert `Res = G_EXTRACT_SUBVECTOR Src, Idx0`.
///
/// \pre setBasicBlock or setMI must have been called.
/// \pre \p Res and \p Src must be generic virtual registers with vector type.
///
/// \return a MachineInstrBuilder for the newly created instruction.
MachineInstrBuilder buildExtractSubvector(const DstOp &Res, const SrcOp &Src,
unsigned Index);

MachineInstrBuilder buildInsert(const DstOp &Res, const SrcOp &Src,
const SrcOp &Op, unsigned Index);

Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/Support/TargetOpcodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,12 @@ HANDLE_TARGET_OPCODE(G_BR)
/// Generic branch to jump table entry.
HANDLE_TARGET_OPCODE(G_BRJT)

/// Generic insert subvector.
HANDLE_TARGET_OPCODE(G_INSERT_SUBVECTOR)

/// Generic extract subvector.
HANDLE_TARGET_OPCODE(G_EXTRACT_SUBVECTOR)

/// Generic insertelement.
HANDLE_TARGET_OPCODE(G_INSERT_VECTOR_ELT)

Expand Down
14 changes: 14 additions & 0 deletions llvm/include/llvm/Target/GenericOpcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -1426,6 +1426,20 @@ def G_WRITE_REGISTER : GenericInstruction {
// Vector ops
//------------------------------------------------------------------------------

// Generic insert subvector.
def G_INSERT_SUBVECTOR : GenericInstruction {
let OutOperandList = (outs type0:$dst);
let InOperandList = (ins type0:$src0, type1:$src1, untyped_imm_0:$idx);
let hasSideEffects = false;
}

// Generic extract subvector.
def G_EXTRACT_SUBVECTOR : GenericInstruction {
let OutOperandList = (outs type0:$dst);
let InOperandList = (ins type0:$src, untyped_imm_0:$idx);
let hasSideEffects = false;
}

// Generic insertelement.
def G_INSERT_VECTOR_ELT : GenericInstruction {
let OutOperandList = (outs type0:$dst);
Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,21 @@ MachineIRBuilder::buildSelect(const DstOp &Res, const SrcOp &Tst,
return buildInstr(TargetOpcode::G_SELECT, {Res}, {Tst, Op0, Op1}, Flags);
}

MachineInstrBuilder MachineIRBuilder::buildInsertSubvector(const DstOp &Res,
const SrcOp &Src0,
const SrcOp &Src1,
unsigned Idx) {
return buildInstr(TargetOpcode::G_INSERT_SUBVECTOR, Res,
{Src0, Src1, uint64_t(Idx)});
}

MachineInstrBuilder MachineIRBuilder::buildExtractSubvector(const DstOp &Res,
const SrcOp &Src,
unsigned Idx) {
return buildInstr(TargetOpcode::G_INSERT_SUBVECTOR, Res,
{Src, uint64_t(Idx)});
}

MachineInstrBuilder
MachineIRBuilder::buildInsertVectorElement(const DstOp &Res, const SrcOp &Val,
const SrcOp &Elt, const SrcOp &Idx) {
Expand Down
98 changes: 98 additions & 0 deletions llvm/lib/CodeGen/MachineVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1603,6 +1603,104 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
report("G_BSWAP size must be a multiple of 16 bits", MI);
break;
}
case TargetOpcode::G_INSERT_SUBVECTOR: {
const MachineOperand &Src0Op = MI->getOperand(1);
if (!Src0Op.isReg()) {
report("G_INSERT_SUBVECTOR first source must be a register", MI);
break;
}

const MachineOperand &Src1Op = MI->getOperand(2);
if (!Src1Op.isReg()) {
report("G_INSERT_SUBVECTOR second source must be a register", MI);
break;
}

const MachineOperand &IndexOp = MI->getOperand(3);
if (!IndexOp.isImm()) {
report("G_INSERT_SUBVECTOR index must be an immediate", MI);
break;
}

LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
LLT Src0Ty = MRI->getType(Src0Op.getReg());
LLT Src1Ty = MRI->getType(Src1Op.getReg());

if (!DstTy.isVector()) {
report("Destination type must be a vector", MI);
break;
}

if (!Src0Ty.isVector()) {
report("First source must be a vector", MI);
break;
}

if (!Src1Ty.isVector()) {
report("Second source must be a vector", MI);
break;
}

if (DstTy != Src0Ty) {
report("Destination type must match the first source vector type", MI);
break;
}

if (Src0Ty.getElementType() != Src1Ty.getElementType()) {
report("Element type of source vectors must be the same", MI);
break;
}

if (IndexOp.getImm() != 0 &&
Src1Ty.getElementCount().getKnownMinValue() % IndexOp.getImm() != 0) {
report("Index must be a multiple of the second source vector's "
"minimum vector length",
MI);
break;
}
break;
}
case TargetOpcode::G_EXTRACT_SUBVECTOR: {
const MachineOperand &SrcOp = MI->getOperand(1);
if (!SrcOp.isReg()) {
report("G_EXTRACT_SUBVECTOR first source must be a register", MI);
break;
}

const MachineOperand &IndexOp = MI->getOperand(2);
if (!IndexOp.isImm()) {
report("G_EXTRACT_SUBVECTOR index must be an immediate", MI);
break;
}

LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
LLT SrcTy = MRI->getType(SrcOp.getReg());

if (!DstTy.isVector()) {
report("Destination type must be a vector", MI);
break;
}

if (!SrcTy.isVector()) {
report("First source must be a vector", MI);
break;
}

if (DstTy.getElementType() != SrcTy.getElementType()) {
report("Element type of vectors must be the same", MI);
break;
}

if (IndexOp.getImm() != 0 &&
SrcTy.getElementCount().getKnownMinValue() % IndexOp.getImm() != 0) {
report("Index must be a multiple of the source vector's minimum vector "
"length",
MI);
break;
}

break;
}
case TargetOpcode::G_SHUFFLE_VECTOR: {
const MachineOperand &MaskOp = MI->getOperand(3);
if (!MaskOp.isShuffleMask()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,12 @@
# DEBUG-NEXT: G_BRJT (opcode {{[0-9]+}}): 2 type indices
# DEBUG-NEXT: .. the first uncovered type index: 2, OK
# DEBUG-NEXT: .. the first uncovered imm index: 0, OK
# DEBUG-NEXT: G_INSERT_SUBVECTOR (opcode {{[0-9]+}}): 2 type indices, 1 imm index
# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
# DEBUG-NEXT: G_EXTRACT_SUBVECTOR (opcode {{[0-9]+}}): 1 type index, 1 imm index
# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
# DEBUG-NEXT: G_INSERT_VECTOR_ELT (opcode {{[0-9]+}}): 3 type indices, 0 imm indices
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
Expand Down
31 changes: 31 additions & 0 deletions llvm/test/MachineVerifier/test_g_extract_subvector.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# RUN: not --crash llc -o - -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s
---
name: g_extract_subvector
tracksRegLiveness: true
liveins:
body: |
bb.0:
%0:_(s32) = G_CONSTANT i32 0
%1:_(<vscale x 2 x s32>) = G_IMPLICIT_DEF
%2:_(<vscale x 1 x s32>) = G_IMPLICIT_DEF

; CHECK: G_EXTRACT_SUBVECTOR first source must be a register
%3:_(<vscale x 2 x s32>) = G_EXTRACT_SUBVECTOR 1, 0

; CHECK: G_EXTRACT_SUBVECTOR index must be an immediate
%4:_(<vscale x 1 x s32>) = G_EXTRACT_SUBVECTOR %2, %0

; CHECK: Destination type must be a vector
%5:_(s32) = G_EXTRACT_SUBVECTOR %2, 0

; CHECK: First source must be a vector
%6:_(<vscale x 2 x s32>) = G_EXTRACT_SUBVECTOR %0, 0

%7:_(<vscale x 1 x s16>) = G_IMPLICIT_DEF

; CHECK: Element type of vectors must be the same
%8:_(<vscale x 2 x s32>) = G_EXTRACT_SUBVECTOR %7, 0

; CHECK: Index must be a multiple of the source vector's minimum vector length
%9:_(<vscale x 4 x s32>) = G_EXTRACT_SUBVECTOR %1, 3
...
43 changes: 43 additions & 0 deletions llvm/test/MachineVerifier/test_g_insert_subvector.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# RUN: not --crash llc -o - -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s

---
name: g_splat_vector
tracksRegLiveness: true
liveins:
body: |
bb.0:
%0:_(s32) = G_CONSTANT i32 0
%1:_(<vscale x 2 x s32>) = G_IMPLICIT_DEF
%2:_(<vscale x 1 x s32>) = G_IMPLICIT_DEF

; CHECK: G_INSERT_SUBVECTOR first source must be a register
%3:_(<vscale x 2 x s32>) = G_INSERT_SUBVECTOR 1, %2, 0

; CHECK: G_INSERT_SUBVECTOR second source must be a register
%4:_(<vscale x 2 x s32>) = G_INSERT_SUBVECTOR %1, 1, 0

; CHECK: G_INSERT_SUBVECTOR index must be an immediate
%5:_(<vscale x 2 x s32>) = G_INSERT_SUBVECTOR %1, %2, %0

; CHECK: Destination type must be a vector
%6:_(s32) = G_INSERT_SUBVECTOR %1, %2, 0

; CHECK: First source must be a vector
%7:_(<vscale x 2 x s32>) = G_INSERT_SUBVECTOR %0, %2, 0

; CHECK: Second source must be a vector
%8:_(<vscale x 2 x s32>) = G_INSERT_SUBVECTOR %1, %0, 0

; CHECK: Destination type must match the first source vector type
%9:_(<vscale x 2 x s32>) = G_INSERT_SUBVECTOR %2, %1, 0

%10:_(<vscale x 1 x s16>) = G_IMPLICIT_DEF

; CHECK: Element type of source vectors must be the same
%11:_(<vscale x 2 x s32>) = G_INSERT_SUBVECTOR %1, %10, 0

%12:_(<vscale x 4 x s32>) = G_IMPLICIT_DEF

; CHECK: Index must be a multiple of the second source vector's minimum vector length
%13:_(<vscale x 4 x s32>) = G_INSERT_SUBVECTOR %12, %1, 3
...