[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:
parent
8f79cdd8da
commit
96049fcf4e
@ -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
|
||||
---------------------------
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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
|
||||
|
||||
1774
llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/shufflevector.ll
Normal file
1774
llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/shufflevector.ll
Normal file
File diff suppressed because it is too large
Load Diff
27
llvm/test/MachineVerifier/test_g_splat_vector.mir
Normal file
27
llvm/test/MachineVerifier/test_g_splat_vector.mir
Normal 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
|
||||
...
|
||||
@ -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());
|
||||
|
||||
@ -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(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user