Skip to content
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

[GlobalISel] Support physical register inputs in nested patterns #121239

Merged
merged 5 commits into from
Jan 5, 2025
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
84 changes: 82 additions & 2 deletions llvm/test/TableGen/GlobalISelEmitter/gisel-physreg-input.td
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,86 @@ class I<dag OOps, dag IOps, list<dag> Pat>
let Pattern = Pat;
}

// Try a nested physical register

// GISEL: GIM_Try,
// GISEL-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
// GISEL-NEXT: GIM_CheckOpcode, /*MI*/0, GIMT_Encode2(TargetOpcode::G_STORE),
// GISEL-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(uint8_t)AtomicOrdering::NotAtomic,
// GISEL-NEXT: // MIs[0] src0
// GISEL-NEXT: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s32,
// GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),
// GISEL-NEXT: // MIs[0] Operand 1
// GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
// GISEL-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
// GISEL-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3,
// GISEL-NEXT: GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_MUL),
// GISEL-NEXT: // MIs[1] Operand 0
// GISEL-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32,
// GISEL-NEXT: // MIs[1] src1
// GISEL-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32,
// GISEL-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),
// GISEL-NEXT: // MIs[1] Operand 2
// GISEL-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32,
// GISEL-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/2, /*RC*/GIMT_Encode2(MyTarget::Special32RegClassID),
// GISEL-NEXT: GIM_CheckIsSafeToFold, /*NumInsns*/1,
// GISEL-NEXT: // (st GPR32:{ *:[i32] }:$src0, (mul:{ *:[i32] } GPR32:{ *:[i32] }:$src1, SPECIAL:{ *:[i32] })) => (MULM_PHYS GPR32:{ *:[i32] }:$src0, GPR32:{ *:[i32] }:$src1)
// GISEL-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::COPY),
// GISEL-NEXT: GIR_AddRegister, /*InsnID*/1, GIMT_Encode2(MyTarget::SPECIAL), /*AddRegisterRegFlags*/GIMT_Encode2(RegState::Define),
// GISEL-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/1, /*OpIdx*/2, // SPECIAL
// GISEL-NEXT: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::MULM_PHYS),
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // src0
// GISEL-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src1
// GISEL-NEXT: GIR_MergeMemOperands, /*InsnID*/0, /*NumInsns*/2, /*MergeInsnID's*/0, 1,
// GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// GISEL-NEXT: // GIR_Coverage, 0,
// GISEL-NEXT: GIR_EraseRootFromParent_Done,
def MULM_PHYS : I<(outs), (ins GPR32:$src0, GPR32:$src1),
[(st GPR32:$src0, (mul GPR32:$src1, SPECIAL))]> {
let Uses = [SPECIAL];
}

// Try nested physical registers and check on duplicated copies

// GISEL: GIM_Try,
// GISEL-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
// GISEL-NEXT: GIM_CheckOpcode, /*MI*/0, GIMT_Encode2(TargetOpcode::G_STORE),
// GISEL-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(uint8_t)AtomicOrdering::NotAtomic,
// GISEL-NEXT: // MIs[0] src0
// GISEL-NEXT: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s32,
// GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),
// GISEL-NEXT: // MIs[0] Operand 1
// GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
// GISEL-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
// GISEL-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3,
// GISEL-NEXT: GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_MUL),
// GISEL-NEXT: // MIs[1] Operand 0
// GISEL-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32,
// GISEL-NEXT: // MIs[1] Operand 1
// GISEL-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32,
// GISEL-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),
// GISEL-NEXT: // MIs[1] Operand 2
// GISEL-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32,
// GISEL-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/2, /*RC*/GIMT_Encode2(MyTarget::Special32RegClassID),
// GISEL-NEXT: GIM_CheckIsSafeToFold, /*NumInsns*/1,
// GISEL-NEXT: // (st GPR32:{ *:[i32] }:$src0, (mul:{ *:[i32] } R0:{ *:[i32] }, SPECIAL:{ *:[i32] })) => (MULMR0_PHYS GPR32:{ *:[i32] }:$src0)
// GISEL-NEXT: GIR_BuildMI, /*InsnID*/2, /*Opcode*/GIMT_Encode2(TargetOpcode::COPY),
// GISEL-NEXT: GIR_AddRegister, /*InsnID*/2, GIMT_Encode2(MyTarget::SPECIAL), /*AddRegisterRegFlags*/GIMT_Encode2(RegState::Define),
// GISEL-NEXT: GIR_Copy, /*NewInsnID*/2, /*OldInsnID*/1, /*OpIdx*/2, // SPECIAL
// GISEL-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::COPY),
// GISEL-NEXT: GIR_AddRegister, /*InsnID*/1, GIMT_Encode2(MyTarget::R0), /*AddRegisterRegFlags*/GIMT_Encode2(RegState::Define),
// GISEL-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/1, /*OpIdx*/1, // R0
// GISEL-NEXT: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::MULMR0_PHYS),
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // src0
// GISEL-NEXT: GIR_MergeMemOperands, /*InsnID*/0, /*NumInsns*/2, /*MergeInsnID's*/0, 1,
// GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// GISEL-NEXT: // GIR_Coverage, 1,
// GISEL-NEXT: GIR_EraseRootFromParent_Done,
def MULMR0_PHYS : I<(outs), (ins GPR32:$src0),
[(st GPR32:$src0, (mul R0, SPECIAL))]> {
let Uses = [R0, SPECIAL];
}

// Try a normal physical register use.

// GISEL: GIM_Try,
Expand All @@ -44,7 +124,7 @@ class I<dag OOps, dag IOps, list<dag> Pat>
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // DstI[dst]
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/1, // src0
// GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// GISEL-NEXT: // GIR_Coverage, 0,
// GISEL-NEXT: // GIR_Coverage, 2,
// GISEL-NEXT: GIR_EraseRootFromParent_Done,
def ADD_PHYS : I<(outs GPR32:$dst), (ins GPR32:$src0),
[(set GPR32:$dst, (add GPR32:$src0, SPECIAL))]> {
Expand Down Expand Up @@ -73,7 +153,7 @@ def ADD_PHYS : I<(outs GPR32:$dst), (ins GPR32:$src0),
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // DstI[dst]
// GISEL-NEXT: GIR_RootToRootCopy, /*OpIdx*/1, // SPECIAL
// GISEL-NEXT: GIR_RootConstrainSelectedInstOperands,
// GISEL-NEXT: // GIR_Coverage, 1,
// GISEL-NEXT: // GIR_Coverage, 3,
// GISEL-NEXT: GIR_EraseRootFromParent_Done,
def MUL_PHYS : I<(outs GPR32:$dst), (ins GPR32:$SPECIAL),
[(set GPR32:$dst, (mul GPR32:$SPECIAL, SPECIAL))]> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1723,7 +1723,6 @@ OperandMatcher &InstructionMatcher::addPhysRegInput(const Record *Reg,
OperandMatcher *OM = new OperandMatcher(*this, OpIdx, "", TempOpIdx);
Operands.emplace_back(OM);
Rule.definePhysRegOperand(Reg, *OM);
PhysRegInputs.emplace_back(Reg, OpIdx);
return *OM;
}

Expand Down
18 changes: 8 additions & 10 deletions llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "Common/CodeGenDAGPatterns.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -492,9 +493,11 @@ class RuleMatcher : public Matcher {
/// the renderers.
StringMap<OperandMatcher *> DefinedOperands;

using PhysRegOperandsTy = SmallMapVector<const Record *, OperandMatcher *, 1>;

/// A map of anonymous physical register operands defined by the matchers that
/// may be referenced by the renderers.
DenseMap<const Record *, OperandMatcher *> PhysRegOperands;
PhysRegOperandsTy PhysRegOperands;

/// ID for the next instruction variable defined with
/// implicitlyDefineInsnVar()
Expand Down Expand Up @@ -695,6 +698,10 @@ class RuleMatcher : public Matcher {
unsigned allocateOutputInsnID() { return NextOutputInsnID++; }
unsigned allocateTempRegID() { return NextTempRegID++; }

iterator_range<PhysRegOperandsTy::const_iterator> physoperands() const {
return make_range(PhysRegOperands.begin(), PhysRegOperands.end());
}

iterator_range<MatchersTy::iterator> insnmatchers() {
return make_range(Matchers.begin(), Matchers.end());
}
Expand Down Expand Up @@ -1756,11 +1763,6 @@ class InstructionMatcher final : public PredicateListMatcher<PredicateMatcher> {
unsigned InsnVarID;
bool AllowNumOpsCheck;

/// PhysRegInputs - List list has an entry for each explicitly specified
/// physreg input to the pattern. The first elt is the Register node, the
/// second is the recorded slot number the input pattern match saved it in.
SmallVector<std::pair<const Record *, unsigned>, 2> PhysRegInputs;

bool canAddNumOperandsCheck() const {
// Add if it's allowed, and:
// - We don't have a variadic operand
Expand Down Expand Up @@ -1802,10 +1804,6 @@ class InstructionMatcher final : public PredicateListMatcher<PredicateMatcher> {
OperandMatcher &addPhysRegInput(const Record *Reg, unsigned OpIdx,
unsigned TempOpIdx);

ArrayRef<std::pair<const Record *, unsigned>> getPhysRegInputs() const {
return PhysRegInputs;
}

StringRef getSymbolicName() const { return SymbolicName; }

unsigned getNumOperandMatchers() const { return Operands.size(); }
Expand Down
8 changes: 4 additions & 4 deletions llvm/utils/TableGen/GlobalISelEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1412,15 +1412,15 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
action_iterator InsertPt = InsertPtOrError.get();
BuildMIAction &DstMIBuilder = *static_cast<BuildMIAction *>(InsertPt->get());

for (auto PhysInput : InsnMatcher.getPhysRegInputs()) {
for (auto PhysOp : M.physoperands()) {
s-barannikov marked this conversation as resolved.
Show resolved Hide resolved
InsertPt = M.insertAction<BuildMIAction>(
InsertPt, M.allocateOutputInsnID(),
&Target.getInstruction(RK.getDef("COPY")));
BuildMIAction &CopyToPhysRegMIBuilder =
*static_cast<BuildMIAction *>(InsertPt->get());
CopyToPhysRegMIBuilder.addRenderer<AddRegisterRenderer>(
Target, PhysInput.first, true);
CopyToPhysRegMIBuilder.addRenderer<CopyPhysRegRenderer>(PhysInput.first);
CopyToPhysRegMIBuilder.addRenderer<AddRegisterRenderer>(Target,
PhysOp.first, true);
CopyToPhysRegMIBuilder.addRenderer<CopyPhysRegRenderer>(PhysOp.first);
}

if (auto Error = importExplicitDefRenderers(InsertPt, M, DstMIBuilder, Dst,
Expand Down
Loading