[GISEL] Add G_VSCALE instruction (#84542)
This commit is contained in:
@@ -607,6 +607,17 @@ See the LLVM LangRef entry on '``llvm.lround.*'`` for details on behaviour.
|
||||
Vector Specific Operations
|
||||
--------------------------
|
||||
|
||||
G_VSCALE
|
||||
^^^^^^^^
|
||||
|
||||
Puts the value of the runtime ``vscale`` multiplied by the value in the source
|
||||
operand into the destination register. This can be useful in determining the
|
||||
actual runtime number of elements in a vector.
|
||||
|
||||
.. code-block::
|
||||
|
||||
%0:_(s32) = G_VSCALE 4
|
||||
|
||||
G_INSERT_SUBVECTOR
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@@ -1143,6 +1143,28 @@ public:
|
||||
MachineInstrBuilder buildInsert(const DstOp &Res, const SrcOp &Src,
|
||||
const SrcOp &Op, unsigned Index);
|
||||
|
||||
/// Build and insert \p Res = G_VSCALE \p MinElts
|
||||
///
|
||||
/// G_VSCALE puts the value of the runtime vscale multiplied by \p MinElts
|
||||
/// into \p Res.
|
||||
///
|
||||
/// \pre setBasicBlock or setMI must have been called.
|
||||
/// \pre \p Res must be a generic virtual register with scalar type.
|
||||
///
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildVScale(const DstOp &Res, unsigned MinElts);
|
||||
|
||||
/// Build and insert \p Res = G_VSCALE \p MinElts
|
||||
///
|
||||
/// G_VSCALE puts the value of the runtime vscale multiplied by \p MinElts
|
||||
/// into \p Res.
|
||||
///
|
||||
/// \pre setBasicBlock or setMI must have been called.
|
||||
/// \pre \p Res must be a generic virtual register with scalar type.
|
||||
///
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildVScale(const DstOp &Res, const ConstantInt &MinElts);
|
||||
|
||||
/// Build and insert a G_INTRINSIC instruction.
|
||||
///
|
||||
/// There are four different opcodes based on combinations of whether the
|
||||
|
||||
@@ -727,6 +727,9 @@ HANDLE_TARGET_OPCODE(G_BR)
|
||||
/// Generic branch to jump table entry.
|
||||
HANDLE_TARGET_OPCODE(G_BRJT)
|
||||
|
||||
/// Generic vscale.
|
||||
HANDLE_TARGET_OPCODE(G_VSCALE)
|
||||
|
||||
/// Generic insert subvector.
|
||||
HANDLE_TARGET_OPCODE(G_INSERT_SUBVECTOR)
|
||||
|
||||
|
||||
@@ -1289,6 +1289,15 @@ def G_MERGE_VALUES : GenericInstruction {
|
||||
let variadicOpsType = type1;
|
||||
}
|
||||
|
||||
// Generic vscale.
|
||||
// Puts the value of the runtime vscale multiplied by the value in the source
|
||||
// operand into the destination register.
|
||||
def G_VSCALE : GenericInstruction {
|
||||
let OutOperandList = (outs type0:$dst);
|
||||
let InOperandList = (ins unknown:$src);
|
||||
let hasSideEffects = false;
|
||||
}
|
||||
|
||||
/// Create a vector from multiple scalar registers. No implicit
|
||||
/// conversion is performed (i.e. the result element type must be the
|
||||
/// same as all source operands)
|
||||
|
||||
@@ -793,6 +793,24 @@ MachineInstrBuilder MachineIRBuilder::buildInsert(const DstOp &Res,
|
||||
return buildInstr(TargetOpcode::G_INSERT, Res, {Src, Op, uint64_t(Index)});
|
||||
}
|
||||
|
||||
MachineInstrBuilder MachineIRBuilder::buildVScale(const DstOp &Res,
|
||||
unsigned MinElts) {
|
||||
|
||||
auto IntN = IntegerType::get(getMF().getFunction().getContext(),
|
||||
Res.getLLTTy(*getMRI()).getScalarSizeInBits());
|
||||
ConstantInt *CI = ConstantInt::get(IntN, MinElts);
|
||||
return buildVScale(Res, *CI);
|
||||
}
|
||||
|
||||
MachineInstrBuilder MachineIRBuilder::buildVScale(const DstOp &Res,
|
||||
const ConstantInt &MinElts) {
|
||||
auto VScale = buildInstr(TargetOpcode::G_VSCALE);
|
||||
VScale->setDebugLoc(DebugLoc());
|
||||
Res.addDefToMIB(*getMRI(), VScale);
|
||||
VScale.addCImm(&MinElts);
|
||||
return VScale;
|
||||
}
|
||||
|
||||
static unsigned getIntrinsicOpcode(bool HasSideEffects, bool IsConvergent) {
|
||||
if (HasSideEffects && IsConvergent)
|
||||
return TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS;
|
||||
|
||||
@@ -1613,6 +1613,17 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
|
||||
report("G_BSWAP size must be a multiple of 16 bits", MI);
|
||||
break;
|
||||
}
|
||||
case TargetOpcode::G_VSCALE: {
|
||||
if (!MI->getOperand(1).isCImm()) {
|
||||
report("G_VSCALE operand must be cimm", MI);
|
||||
break;
|
||||
}
|
||||
if (MI->getOperand(1).getCImm()->isZero()) {
|
||||
report("G_VSCALE immediate cannot be zero", MI);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TargetOpcode::G_INSERT_SUBVECTOR: {
|
||||
const MachineOperand &Src0Op = MI->getOperand(1);
|
||||
if (!Src0Op.isReg()) {
|
||||
|
||||
@@ -616,6 +616,9 @@
|
||||
# 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_VSCALE (opcode {{[0-9]+}}): 1 type index, 0 imm indices
|
||||
# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
|
||||
# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
|
||||
# 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
|
||||
|
||||
15
llvm/test/MachineVerifier/test_g_vscale.mir
Normal file
15
llvm/test/MachineVerifier/test_g_vscale.mir
Normal file
@@ -0,0 +1,15 @@
|
||||
# RUN: not --crash llc -verify-machineinstrs -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
|
||||
|
||||
---
|
||||
name: g_vscale
|
||||
body: |
|
||||
bb.0:
|
||||
|
||||
%1:_(s32) = G_CONSTANT i32 4
|
||||
|
||||
; CHECK: G_VSCALE operand must be cimm
|
||||
%2:_(s32) = G_VSCALE %1
|
||||
|
||||
; CHECK: G_VSCALE immediate cannot be zero
|
||||
%3:_(s32) = G_VSCALE i32 0
|
||||
...
|
||||
Reference in New Issue
Block a user