Skip to content

Commit d0dc29c

Browse files
authored
[TableGen] HasOneUse builtin predicate on PatFrags (#91578)
This predicate tells GlobalISelEmitter and DAGISelEmitter to check that the instruction to emit has only one use of its result. This can be used on a PatFrag instead of defining custom predicates for both emitters per record that requires it.
1 parent 1553b21 commit d0dc29c

File tree

8 files changed

+82
-10
lines changed

8 files changed

+82
-10
lines changed

llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ enum {
212212
/// - InsnID(ULEB128) - Instruction ID
213213
GIM_CheckHasNoUse,
214214

215+
/// Check if there's one use of the first result.
216+
/// - InsnID(ULEB128) - Instruction ID
217+
GIM_CheckHasOneUse,
218+
215219
/// Check the type for the specified operand
216220
/// - InsnID(ULEB128) - Instruction ID
217221
/// - OpIdx(ULEB128) - Operand index

llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,24 @@ bool GIMatchTableExecutor::executeMatchTable(
468468
if (handleReject() == RejectAndGiveUp)
469469
return false;
470470
}
471+
break;
472+
}
473+
case GIM_CheckHasOneUse: {
474+
uint64_t InsnID = readULEB();
475+
476+
DEBUG_WITH_TYPE(TgtExecutor::getName(),
477+
dbgs() << CurrentIdx << ": GIM_CheckHasOneUse(MIs["
478+
<< InsnID << "]\n");
479+
480+
const MachineInstr *MI = State.MIs[InsnID];
481+
assert(MI && "Used insn before defined");
482+
assert(MI->getNumDefs() > 0 && "No defs");
483+
const Register Res = MI->getOperand(0).getReg();
471484

485+
if (!MRI.hasOneNonDBGUse(Res)) {
486+
if (handleReject() == RejectAndGiveUp)
487+
return false;
488+
}
472489
break;
473490
}
474491
case GIM_CheckAtomicOrdering: {

llvm/include/llvm/Target/TargetSelectionDAG.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,9 @@ class PatFrags<dag ops, list<dag> frags, code pred = [{}],
884884
// If set to true, a predicate is added that checks for the absence of use of
885885
// the first result.
886886
bit HasNoUse = ?;
887+
// If set to true, a predicate is added that checks for the sole use of
888+
// the first result.
889+
bit HasOneUse = ?;
887890

888891
// Is the desired pre-packaged predicate for a load?
889892
bit IsLoad = ?;

llvm/test/TableGen/predicate-patfags.td

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
// RUN: llvm-tblgen -gen-dag-isel -I %p/../../include -I %p/Common %s 2>&1 | FileCheck -check-prefix=SDAG %s
2-
// RUN: llvm-tblgen -gen-global-isel -I %p/../../include -I %p/Common %s 2>&1 | FileCheck -check-prefix=GISEL %s
1+
// RUN: llvm-tblgen -gen-dag-isel -I %p/../../include -I %p/Common %s 2>&1 | FileCheck -check-prefixes=SDAG,SCUSTOM %s
2+
// RUN: llvm-tblgen -gen-dag-isel -I %p/../../include -I %p/Common %s -DHASONEUSE 2>&1 | FileCheck -check-prefixes=SDAG,SBUILTIN %s
3+
// RUN: llvm-tblgen -gen-global-isel -I %p/../../include -I %p/Common %s 2>&1 | FileCheck -check-prefixes=GISEL,GCUSTOM %s
4+
// RUN: llvm-tblgen -gen-global-isel -I %p/../../include -I %p/Common %s -DHASONEUSE 2>&1 | FileCheck -check-prefixes=GISEL,GBUILTIN %s
35

46
include "llvm/Target/Target.td"
57
include "GlobalISelEmitterCommon.td"
@@ -31,11 +33,16 @@ def : GINodeEquiv<G_TGT_MUL24, TGTmul24_impl>;
3133

3234
def TGTmul24_oneuse : PatFrag<
3335
(ops node:$src0, node:$src1),
34-
(TGTmul24 $src0, $src1),
35-
[{ return N->hasOneUse(); }]> {
36+
(TGTmul24 $src0, $src1)
37+
#ifndef HASONEUSE
38+
, [{ return N->hasOneUse(); }]> {
3639
let GISelPredicateCode = [{
3740
return MRI->hasOneNonDBGUse(MI.getOperand(0).getReg());
3841
}];
42+
#else
43+
> {
44+
let HasOneUse = 1;
45+
#endif
3946
}
4047

4148
// SDAG: OPC_CheckOpcode, TARGET_VAL(ISD::INTRINSIC_W_CHAIN),
@@ -44,19 +51,26 @@ def TGTmul24_oneuse : PatFrag<
4451
// SDAG: OPC_CheckOpcode, TARGET_VAL(TargetISD::MUL24),
4552
// SDAG: OPC_CheckPredicate0, // Predicate_TGTmul24_oneuse
4653

54+
// SCUSTOM: return N->hasOneUse();
55+
// SBUILTIN: if (!SDValue(N, 0).hasOneUse()) return false;
56+
4757
// GISEL: GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS),
4858
// GISEL: GIM_CheckIntrinsicID, /*MI*/1, /*Op*/1, GIMT_Encode2(Intrinsic::tgt_mul24),
49-
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
59+
// GBUILTIN: GIM_CheckHasOneUse, /*MI*/1,
60+
// GCUSTOM: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
5061

5162
// GISEL: GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS),
5263
// GISEL: GIM_CheckIntrinsicID, /*MI*/1, /*Op*/1, GIMT_Encode2(Intrinsic::tgt_mul24),
53-
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
64+
// GBUILTIN: GIM_CheckHasOneUse, /*MI*/1,
65+
// GCUSTOM: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
5466

5567
// GISEL: GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(MyTarget::G_TGT_MUL24),
56-
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
68+
// GBUILTIN: GIM_CheckHasOneUse, /*MI*/1,
69+
// GCUSTOM: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
5770

5871
// GISEL: GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(MyTarget::G_TGT_MUL24),
59-
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
72+
// GBUILTIN: GIM_CheckHasOneUse, /*MI*/1,
73+
// GCUSTOM: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
6074
def inst_mad24 : I<
6175
(outs GPR32:$dst),
6276
(ins GPR32:$src0, GPR32:$src1, GPR32:$src2),

llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -903,7 +903,7 @@ TreePredicateFn::TreePredicateFn(TreePattern *N) : PatFragRec(N) {
903903
}
904904

905905
bool TreePredicateFn::hasPredCode() const {
906-
return isLoad() || isStore() || isAtomic() || hasNoUse() ||
906+
return isLoad() || isStore() || isAtomic() || hasNoUse() || hasOneUse() ||
907907
!PatFragRec->getRecord()->getValueAsString("PredicateCode").empty();
908908
}
909909

@@ -1140,6 +1140,8 @@ std::string TreePredicateFn::getPredCode() const {
11401140

11411141
if (hasNoUse())
11421142
Code += "if (!SDValue(N, 0).use_empty()) return false;\n";
1143+
if (hasOneUse())
1144+
Code += "if (!SDValue(N, 0).hasOneUse()) return false;\n";
11431145

11441146
std::string PredicateCode =
11451147
std::string(PatFragRec->getRecord()->getValueAsString("PredicateCode"));
@@ -1187,6 +1189,9 @@ bool TreePredicateFn::usesOperands() const {
11871189
bool TreePredicateFn::hasNoUse() const {
11881190
return isPredefinedPredicateEqualTo("HasNoUse", true);
11891191
}
1192+
bool TreePredicateFn::hasOneUse() const {
1193+
return isPredefinedPredicateEqualTo("HasOneUse", true);
1194+
}
11901195
bool TreePredicateFn::isLoad() const {
11911196
return isPredefinedPredicateEqualTo("IsLoad", true);
11921197
}

llvm/utils/TableGen/Common/CodeGenDAGPatterns.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,8 @@ class TreePredicateFn {
533533

534534
// Check if the HasNoUse predicate is set.
535535
bool hasNoUse() const;
536+
// Check if the HasOneUse predicate is set.
537+
bool hasOneUse() const;
536538

537539
// Is the desired predefined predicate for a load?
538540
bool isLoad() const;

llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,7 @@ class PredicateMatcher {
806806
IPM_MemoryAlignment,
807807
IPM_VectorSplatImm,
808808
IPM_NoUse,
809+
IPM_OneUse,
809810
IPM_GenericPredicate,
810811
IPM_MIFlags,
811812
OPM_SameOperand,
@@ -1691,6 +1692,28 @@ class NoUsePredicateMatcher : public InstructionPredicateMatcher {
16911692
}
16921693
};
16931694

1695+
/// Generates code to check that the first result has only one use.
1696+
class OneUsePredicateMatcher : public InstructionPredicateMatcher {
1697+
public:
1698+
OneUsePredicateMatcher(unsigned InsnVarID)
1699+
: InstructionPredicateMatcher(IPM_OneUse, InsnVarID) {}
1700+
1701+
static bool classof(const PredicateMatcher *P) {
1702+
return P->getKind() == IPM_OneUse;
1703+
}
1704+
1705+
bool isIdentical(const PredicateMatcher &B) const override {
1706+
return InstructionPredicateMatcher::isIdentical(B);
1707+
}
1708+
1709+
void emitPredicateOpcodes(MatchTable &Table,
1710+
RuleMatcher &Rule) const override {
1711+
Table << MatchTable::Opcode("GIM_CheckHasOneUse")
1712+
<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1713+
<< MatchTable::LineBreak;
1714+
}
1715+
};
1716+
16941717
/// Generates code to check that a set of predicates and operands match for a
16951718
/// particular instruction.
16961719
///

llvm/utils/TableGen/GlobalISelEmitter.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ static Error isTrivialOperatorNode(const TreePatternNode &N) {
207207
if (Predicate.isImmediatePattern())
208208
continue;
209209

210-
if (Predicate.hasNoUse())
210+
if (Predicate.hasNoUse() || Predicate.hasOneUse())
211211
continue;
212212

213213
if (Predicate.isNonExtLoad() || Predicate.isAnyExtLoad() ||
@@ -782,6 +782,10 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
782782
InsnMatcher.addPredicate<NoUsePredicateMatcher>();
783783
HasAddedBuiltinMatcher = true;
784784
}
785+
if (Predicate.hasOneUse()) {
786+
InsnMatcher.addPredicate<OneUsePredicateMatcher>();
787+
HasAddedBuiltinMatcher = true;
788+
}
785789

786790
if (Predicate.hasGISelPredicateCode()) {
787791
if (Predicate.usesOperands()) {

0 commit comments

Comments
 (0)