[GISEL] Add IRTranslation for shufflevector on scalable vector types (#80378)

Recommits llvm/llvm-project#80378 which was reverted in
llvm/llvm-project#84330. The problem was that the change in
llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir used
217 as an opcode instead of a regex.
This commit is contained in:
Michael Maitland 2024-03-07 09:50:29 -05:00
parent 8f79cdd8da
commit 96049fcf4e
15 changed files with 1890 additions and 21 deletions

View File

@ -639,6 +639,11 @@ Concatenate two vectors and shuffle the elements according to the mask operand.
The mask operand should be an IR Constant which exactly matches the
corresponding mask for the IR shufflevector instruction.
G_SPLAT_VECTOR
^^^^^^^^^^^^^^^^
Create a vector where all elements are the scalar from the source operand.
Vector Reduction Operations
---------------------------

View File

@ -1063,8 +1063,7 @@ public:
/// Build and insert \p Res = G_BUILD_VECTOR with \p Src replicated to fill
/// the number of elements
MachineInstrBuilder buildSplatVector(const DstOp &Res,
const SrcOp &Src);
MachineInstrBuilder buildSplatBuildVector(const DstOp &Res, const SrcOp &Src);
/// Build and insert \p Res = G_BUILD_VECTOR_TRUNC \p Op0, ...
///
@ -1099,6 +1098,15 @@ public:
MachineInstrBuilder buildShuffleVector(const DstOp &Res, const SrcOp &Src1,
const SrcOp &Src2, ArrayRef<int> Mask);
/// Build and insert \p Res = G_SPLAT_VECTOR \p Val
///
/// \pre setBasicBlock or setMI must have been called.
/// \pre \p Res must be a generic virtual register with vector type.
/// \pre \p Val must be a generic virtual register with scalar type.
///
/// \return a MachineInstrBuilder for the newly created instruction.
MachineInstrBuilder buildSplatVector(const DstOp &Res, const SrcOp &Val);
/// Build and insert \p Res = G_CONCAT_VECTORS \p Op0, ...
///
/// G_CONCAT_VECTORS creates a vector from the concatenation of 2 or more

View File

@ -736,6 +736,9 @@ HANDLE_TARGET_OPCODE(G_EXTRACT_VECTOR_ELT)
/// Generic shufflevector.
HANDLE_TARGET_OPCODE(G_SHUFFLE_VECTOR)
/// Generic splatvector.
HANDLE_TARGET_OPCODE(G_SPLAT_VECTOR)
/// Generic count trailing zeroes.
HANDLE_TARGET_OPCODE(G_CTTZ)

View File

@ -1450,6 +1450,13 @@ def G_SHUFFLE_VECTOR: GenericInstruction {
let hasSideEffects = false;
}
// Generic splatvector.
def G_SPLAT_VECTOR: GenericInstruction {
let OutOperandList = (outs type0:$dst);
let InOperandList = (ins type1:$val);
let hasSideEffects = false;
}
//------------------------------------------------------------------------------
// Vector reductions
//------------------------------------------------------------------------------

View File

@ -309,7 +309,7 @@ MachineInstrBuilder CSEMIRBuilder::buildConstant(const DstOp &Res,
// For vectors, CSE the element only for now.
LLT Ty = Res.getLLTTy(*getMRI());
if (Ty.isVector())
return buildSplatVector(Res, buildConstant(Ty.getElementType(), Val));
return buildSplatBuildVector(Res, buildConstant(Ty.getElementType(), Val));
FoldingSetNodeID ID;
GISelInstProfileBuilder ProfBuilder(ID, *getMRI());
@ -336,7 +336,7 @@ MachineInstrBuilder CSEMIRBuilder::buildFConstant(const DstOp &Res,
// For vectors, CSE the element only for now.
LLT Ty = Res.getLLTTy(*getMRI());
if (Ty.isVector())
return buildSplatVector(Res, buildFConstant(Ty.getElementType(), Val));
return buildSplatBuildVector(Res, buildFConstant(Ty.getElementType(), Val));
FoldingSetNodeID ID;
GISelInstProfileBuilder ProfBuilder(ID, *getMRI());

View File

@ -1598,10 +1598,10 @@ bool IRTranslator::translateGetElementPtr(const User &U,
// We might need to splat the base pointer into a vector if the offsets
// are vectors.
if (WantSplatVector && !PtrTy.isVector()) {
BaseReg =
MIRBuilder
.buildSplatVector(LLT::fixed_vector(VectorWidth, PtrTy), BaseReg)
.getReg(0);
BaseReg = MIRBuilder
.buildSplatBuildVector(LLT::fixed_vector(VectorWidth, PtrTy),
BaseReg)
.getReg(0);
PtrIRTy = FixedVectorType::get(PtrIRTy, VectorWidth);
PtrTy = getLLTForType(*PtrIRTy, *DL);
OffsetIRTy = DL->getIndexType(PtrIRTy);
@ -1639,8 +1639,10 @@ bool IRTranslator::translateGetElementPtr(const User &U,
LLT IdxTy = MRI->getType(IdxReg);
if (IdxTy != OffsetTy) {
if (!IdxTy.isVector() && WantSplatVector) {
IdxReg = MIRBuilder.buildSplatVector(
OffsetTy.changeElementType(IdxTy), IdxReg).getReg(0);
IdxReg = MIRBuilder
.buildSplatBuildVector(OffsetTy.changeElementType(IdxTy),
IdxReg)
.getReg(0);
}
IdxReg = MIRBuilder.buildSExtOrTrunc(OffsetTy, IdxReg).getReg(0);
@ -2997,6 +2999,19 @@ bool IRTranslator::translateExtractElement(const User &U,
bool IRTranslator::translateShuffleVector(const User &U,
MachineIRBuilder &MIRBuilder) {
// A ShuffleVector that has operates on scalable vectors is a splat vector
// where the value of the splat vector is the 0th element of the first
// operand, since the index mask operand is the zeroinitializer (undef and
// poison are treated as zeroinitializer here).
if (U.getOperand(0)->getType()->isScalableTy()) {
Value *Op0 = U.getOperand(0);
auto SplatVal = MIRBuilder.buildExtractVectorElementConstant(
LLT::scalar(Op0->getType()->getScalarSizeInBits()),
getOrCreateVReg(*Op0), 0);
MIRBuilder.buildSplatVector(getOrCreateVReg(U), SplatVal);
return true;
}
ArrayRef<int> Mask;
if (auto *SVI = dyn_cast<ShuffleVectorInst>(&U))
Mask = SVI->getShuffleMask();

View File

@ -8391,7 +8391,7 @@ static Register getMemsetValue(Register Val, LLT Ty, MachineIRBuilder &MIB) {
// For vector types create a G_BUILD_VECTOR.
if (Ty.isVector())
Val = MIB.buildSplatVector(Ty, Val).getReg(0);
Val = MIB.buildSplatBuildVector(Ty, Val).getReg(0);
return Val;
}

View File

@ -326,7 +326,7 @@ MachineInstrBuilder MachineIRBuilder::buildConstant(const DstOp &Res,
auto Const = buildInstr(TargetOpcode::G_CONSTANT)
.addDef(getMRI()->createGenericVirtualRegister(EltTy))
.addCImm(&Val);
return buildSplatVector(Res, Const);
return buildSplatBuildVector(Res, Const);
}
auto Const = buildInstr(TargetOpcode::G_CONSTANT);
@ -363,7 +363,7 @@ MachineInstrBuilder MachineIRBuilder::buildFConstant(const DstOp &Res,
.addDef(getMRI()->createGenericVirtualRegister(EltTy))
.addFPImm(&Val);
return buildSplatVector(Res, Const);
return buildSplatBuildVector(Res, Const);
}
auto Const = buildInstr(TargetOpcode::G_FCONSTANT);
@ -711,8 +711,8 @@ MachineIRBuilder::buildBuildVectorConstant(const DstOp &Res,
return buildInstr(TargetOpcode::G_BUILD_VECTOR, Res, TmpVec);
}
MachineInstrBuilder MachineIRBuilder::buildSplatVector(const DstOp &Res,
const SrcOp &Src) {
MachineInstrBuilder MachineIRBuilder::buildSplatBuildVector(const DstOp &Res,
const SrcOp &Src) {
SmallVector<SrcOp, 8> TmpVec(Res.getLLTTy(*getMRI()).getNumElements(), Src);
return buildInstr(TargetOpcode::G_BUILD_VECTOR, Res, TmpVec);
}
@ -742,6 +742,14 @@ MachineInstrBuilder MachineIRBuilder::buildShuffleSplat(const DstOp &Res,
return buildShuffleVector(DstTy, InsElt, UndefVec, ZeroMask);
}
MachineInstrBuilder MachineIRBuilder::buildSplatVector(const DstOp &Res,
const SrcOp &Src) {
LLT DstTy = Res.getLLTTy(*getMRI());
assert(Src.getLLTTy(*getMRI()) == DstTy.getElementType() &&
"Expected Src to match Dst elt ty");
return buildInstr(TargetOpcode::G_SPLAT_VECTOR, Res, Src);
}
MachineInstrBuilder MachineIRBuilder::buildShuffleVector(const DstOp &Res,
const SrcOp &Src1,
const SrcOp &Src2,

View File

@ -1640,6 +1640,24 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
break;
}
case TargetOpcode::G_SPLAT_VECTOR: {
LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
LLT SrcTy = MRI->getType(MI->getOperand(1).getReg());
if (!DstTy.isScalableVector())
report("Destination type must be a scalable vector", MI);
if (!SrcTy.isScalar())
report("Source type must be a scalar", MI);
if (DstTy.getScalarType() != SrcTy)
report("Element type of the destination must be the same type as the "
"source type",
MI);
break;
}
case TargetOpcode::G_DYN_STACKALLOC: {
const MachineOperand &DstOp = MI->getOperand(0);
const MachineOperand &AllocOp = MI->getOperand(1);

View File

@ -20920,7 +20920,8 @@ bool RISCVTargetLowering::fallBackToDAGISel(const Instruction &Inst) const {
unsigned Op = Inst.getOpcode();
if (Op == Instruction::Add || Op == Instruction::Sub ||
Op == Instruction::And || Op == Instruction::Or ||
Op == Instruction::Xor || Op == Instruction::InsertElement)
Op == Instruction::Xor || Op == Instruction::InsertElement ||
Op == Instruction::Xor || Op == Instruction::ShuffleVector)
return false;
if (Inst.getType()->isScalableTy())

View File

@ -625,6 +625,9 @@
# DEBUG-NEXT: G_SHUFFLE_VECTOR (opcode {{[0-9]+}}): 2 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
# DEBUG-NEXT: G_SPLAT_VECTOR (opcode {{[0-9]+}}): 2 type indices, 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_CTTZ (opcode {{[0-9]+}}): 2 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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
# RUN: not --crash llc -o - -mtriple=arm64 -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s
# REQUIRES: aarch64-registered-target
---
name: g_splat_vector
tracksRegLiveness: true
liveins:
body: |
bb.0:
%0:_(s32) = G_CONSTANT i32 0
%1:_(<2 x s32>) = G_IMPLICIT_DEF
%2:_(<vscale x 2 x s32>) = G_IMPLICIT_DEF
; CHECK: Destination type must be a scalable vector
%3:_(s32) = G_SPLAT_VECTOR %0
; CHECK: Destination type must be a scalable vector
%4:_(<2 x s32>) = G_SPLAT_VECTOR %0
; CHECK: Source type must be a scalar
%5:_(<vscale x 2 x s32>) = G_SPLAT_VECTOR %1
; CHECK: Source type must be a scalar
%6:_(<vscale x 2 x s32>) = G_SPLAT_VECTOR %2
; CHECK: Element type of the destination must be the same type as the source type
%7:_(<vscale x 2 x s64>) = G_SPLAT_VECTOR %0
...

View File

@ -147,9 +147,9 @@ TEST_F(AArch64GISelMITest, LowerRotatesVector) {
LLT S32 = LLT::scalar(32);
LLT V4S32 = LLT::fixed_vector(4, S32);
auto SrcTrunc = B.buildTrunc(S32, Copies[0]);
auto Src = B.buildSplatVector(V4S32, SrcTrunc);
auto Src = B.buildSplatBuildVector(V4S32, SrcTrunc);
auto AmtTrunc = B.buildTrunc(S32, Copies[1]);
auto Amt = B.buildSplatVector(V4S32, AmtTrunc);
auto Amt = B.buildSplatBuildVector(V4S32, AmtTrunc);
auto ROTR = B.buildInstr(TargetOpcode::G_ROTR, {V4S32}, {Src, Amt});
AInfo Info(MF->getSubtarget());

View File

@ -61,7 +61,7 @@ TEST_F(AArch64GISelMITest, MatchIntConstantSplat) {
LLT v4s64 = LLT::fixed_vector(4, s64);
MachineInstrBuilder FortyTwoSplat =
B.buildSplatVector(v4s64, B.buildConstant(s64, 42));
B.buildSplatBuildVector(v4s64, B.buildConstant(s64, 42));
int64_t Cst;
EXPECT_TRUE(mi_match(FortyTwoSplat.getReg(0), *MRI, m_ICstOrSplat(Cst)));
EXPECT_EQ(Cst, 42);
@ -625,7 +625,7 @@ TEST_F(AArch64GISelMITest, MatchSpecificConstantSplat) {
LLT v4s64 = LLT::fixed_vector(4, s64);
MachineInstrBuilder FortyTwoSplat =
B.buildSplatVector(v4s64, B.buildConstant(s64, 42));
B.buildSplatBuildVector(v4s64, B.buildConstant(s64, 42));
MachineInstrBuilder FortyTwo = B.buildConstant(s64, 42);
EXPECT_TRUE(mi_match(FortyTwoSplat.getReg(0), *MRI, m_SpecificICstSplat(42)));
@ -655,7 +655,7 @@ TEST_F(AArch64GISelMITest, MatchSpecificConstantOrSplat) {
LLT v4s64 = LLT::fixed_vector(4, s64);
MachineInstrBuilder FortyTwoSplat =
B.buildSplatVector(v4s64, B.buildConstant(s64, 42));
B.buildSplatBuildVector(v4s64, B.buildConstant(s64, 42));
MachineInstrBuilder FortyTwo = B.buildConstant(s64, 42);
EXPECT_TRUE(