mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 01:06:06 +00:00
[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.
This commit is contained in:
parent
1553b21f6d
commit
d0dc29c208
@ -212,6 +212,10 @@ enum {
|
||||
/// - InsnID(ULEB128) - Instruction ID
|
||||
GIM_CheckHasNoUse,
|
||||
|
||||
/// Check if there's one use of the first result.
|
||||
/// - InsnID(ULEB128) - Instruction ID
|
||||
GIM_CheckHasOneUse,
|
||||
|
||||
/// Check the type for the specified operand
|
||||
/// - InsnID(ULEB128) - Instruction ID
|
||||
/// - OpIdx(ULEB128) - Operand index
|
||||
|
@ -468,7 +468,24 @@ bool GIMatchTableExecutor::executeMatchTable(
|
||||
if (handleReject() == RejectAndGiveUp)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GIM_CheckHasOneUse: {
|
||||
uint64_t InsnID = readULEB();
|
||||
|
||||
DEBUG_WITH_TYPE(TgtExecutor::getName(),
|
||||
dbgs() << CurrentIdx << ": GIM_CheckHasOneUse(MIs["
|
||||
<< InsnID << "]\n");
|
||||
|
||||
const MachineInstr *MI = State.MIs[InsnID];
|
||||
assert(MI && "Used insn before defined");
|
||||
assert(MI->getNumDefs() > 0 && "No defs");
|
||||
const Register Res = MI->getOperand(0).getReg();
|
||||
|
||||
if (!MRI.hasOneNonDBGUse(Res)) {
|
||||
if (handleReject() == RejectAndGiveUp)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GIM_CheckAtomicOrdering: {
|
||||
|
@ -884,6 +884,9 @@ class PatFrags<dag ops, list<dag> frags, code pred = [{}],
|
||||
// If set to true, a predicate is added that checks for the absence of use of
|
||||
// the first result.
|
||||
bit HasNoUse = ?;
|
||||
// If set to true, a predicate is added that checks for the sole use of
|
||||
// the first result.
|
||||
bit HasOneUse = ?;
|
||||
|
||||
// Is the desired pre-packaged predicate for a load?
|
||||
bit IsLoad = ?;
|
||||
|
@ -1,5 +1,7 @@
|
||||
// RUN: llvm-tblgen -gen-dag-isel -I %p/../../include -I %p/Common %s 2>&1 | FileCheck -check-prefix=SDAG %s
|
||||
// RUN: llvm-tblgen -gen-global-isel -I %p/../../include -I %p/Common %s 2>&1 | FileCheck -check-prefix=GISEL %s
|
||||
// RUN: llvm-tblgen -gen-dag-isel -I %p/../../include -I %p/Common %s 2>&1 | FileCheck -check-prefixes=SDAG,SCUSTOM %s
|
||||
// RUN: llvm-tblgen -gen-dag-isel -I %p/../../include -I %p/Common %s -DHASONEUSE 2>&1 | FileCheck -check-prefixes=SDAG,SBUILTIN %s
|
||||
// RUN: llvm-tblgen -gen-global-isel -I %p/../../include -I %p/Common %s 2>&1 | FileCheck -check-prefixes=GISEL,GCUSTOM %s
|
||||
// RUN: llvm-tblgen -gen-global-isel -I %p/../../include -I %p/Common %s -DHASONEUSE 2>&1 | FileCheck -check-prefixes=GISEL,GBUILTIN %s
|
||||
|
||||
include "llvm/Target/Target.td"
|
||||
include "GlobalISelEmitterCommon.td"
|
||||
@ -31,11 +33,16 @@ def : GINodeEquiv<G_TGT_MUL24, TGTmul24_impl>;
|
||||
|
||||
def TGTmul24_oneuse : PatFrag<
|
||||
(ops node:$src0, node:$src1),
|
||||
(TGTmul24 $src0, $src1),
|
||||
[{ return N->hasOneUse(); }]> {
|
||||
(TGTmul24 $src0, $src1)
|
||||
#ifndef HASONEUSE
|
||||
, [{ return N->hasOneUse(); }]> {
|
||||
let GISelPredicateCode = [{
|
||||
return MRI->hasOneNonDBGUse(MI.getOperand(0).getReg());
|
||||
}];
|
||||
#else
|
||||
> {
|
||||
let HasOneUse = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// SDAG: OPC_CheckOpcode, TARGET_VAL(ISD::INTRINSIC_W_CHAIN),
|
||||
@ -44,19 +51,26 @@ def TGTmul24_oneuse : PatFrag<
|
||||
// SDAG: OPC_CheckOpcode, TARGET_VAL(TargetISD::MUL24),
|
||||
// SDAG: OPC_CheckPredicate0, // Predicate_TGTmul24_oneuse
|
||||
|
||||
// GISEL: GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS),
|
||||
// GISEL: GIM_CheckIntrinsicID, /*MI*/1, /*Op*/1, GIMT_Encode2(Intrinsic::tgt_mul24),
|
||||
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
|
||||
// SCUSTOM: return N->hasOneUse();
|
||||
// SBUILTIN: if (!SDValue(N, 0).hasOneUse()) return false;
|
||||
|
||||
// GISEL: GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS),
|
||||
// GISEL: GIM_CheckIntrinsicID, /*MI*/1, /*Op*/1, GIMT_Encode2(Intrinsic::tgt_mul24),
|
||||
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
|
||||
// GBUILTIN: GIM_CheckHasOneUse, /*MI*/1,
|
||||
// GCUSTOM: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
|
||||
|
||||
// GISEL: GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS),
|
||||
// GISEL: GIM_CheckIntrinsicID, /*MI*/1, /*Op*/1, GIMT_Encode2(Intrinsic::tgt_mul24),
|
||||
// GBUILTIN: GIM_CheckHasOneUse, /*MI*/1,
|
||||
// GCUSTOM: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
|
||||
|
||||
// GISEL: GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(MyTarget::G_TGT_MUL24),
|
||||
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
|
||||
// GBUILTIN: GIM_CheckHasOneUse, /*MI*/1,
|
||||
// GCUSTOM: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
|
||||
|
||||
// GISEL: GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(MyTarget::G_TGT_MUL24),
|
||||
// GISEL: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
|
||||
// GBUILTIN: GIM_CheckHasOneUse, /*MI*/1,
|
||||
// GCUSTOM: GIM_CheckCxxInsnPredicate, /*MI*/1, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_TGTmul24_oneuse),
|
||||
def inst_mad24 : I<
|
||||
(outs GPR32:$dst),
|
||||
(ins GPR32:$src0, GPR32:$src1, GPR32:$src2),
|
||||
|
@ -903,7 +903,7 @@ TreePredicateFn::TreePredicateFn(TreePattern *N) : PatFragRec(N) {
|
||||
}
|
||||
|
||||
bool TreePredicateFn::hasPredCode() const {
|
||||
return isLoad() || isStore() || isAtomic() || hasNoUse() ||
|
||||
return isLoad() || isStore() || isAtomic() || hasNoUse() || hasOneUse() ||
|
||||
!PatFragRec->getRecord()->getValueAsString("PredicateCode").empty();
|
||||
}
|
||||
|
||||
@ -1140,6 +1140,8 @@ std::string TreePredicateFn::getPredCode() const {
|
||||
|
||||
if (hasNoUse())
|
||||
Code += "if (!SDValue(N, 0).use_empty()) return false;\n";
|
||||
if (hasOneUse())
|
||||
Code += "if (!SDValue(N, 0).hasOneUse()) return false;\n";
|
||||
|
||||
std::string PredicateCode =
|
||||
std::string(PatFragRec->getRecord()->getValueAsString("PredicateCode"));
|
||||
@ -1187,6 +1189,9 @@ bool TreePredicateFn::usesOperands() const {
|
||||
bool TreePredicateFn::hasNoUse() const {
|
||||
return isPredefinedPredicateEqualTo("HasNoUse", true);
|
||||
}
|
||||
bool TreePredicateFn::hasOneUse() const {
|
||||
return isPredefinedPredicateEqualTo("HasOneUse", true);
|
||||
}
|
||||
bool TreePredicateFn::isLoad() const {
|
||||
return isPredefinedPredicateEqualTo("IsLoad", true);
|
||||
}
|
||||
|
@ -533,6 +533,8 @@ public:
|
||||
|
||||
// Check if the HasNoUse predicate is set.
|
||||
bool hasNoUse() const;
|
||||
// Check if the HasOneUse predicate is set.
|
||||
bool hasOneUse() const;
|
||||
|
||||
// Is the desired predefined predicate for a load?
|
||||
bool isLoad() const;
|
||||
|
@ -806,6 +806,7 @@ public:
|
||||
IPM_MemoryAlignment,
|
||||
IPM_VectorSplatImm,
|
||||
IPM_NoUse,
|
||||
IPM_OneUse,
|
||||
IPM_GenericPredicate,
|
||||
IPM_MIFlags,
|
||||
OPM_SameOperand,
|
||||
@ -1691,6 +1692,28 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// Generates code to check that the first result has only one use.
|
||||
class OneUsePredicateMatcher : public InstructionPredicateMatcher {
|
||||
public:
|
||||
OneUsePredicateMatcher(unsigned InsnVarID)
|
||||
: InstructionPredicateMatcher(IPM_OneUse, InsnVarID) {}
|
||||
|
||||
static bool classof(const PredicateMatcher *P) {
|
||||
return P->getKind() == IPM_OneUse;
|
||||
}
|
||||
|
||||
bool isIdentical(const PredicateMatcher &B) const override {
|
||||
return InstructionPredicateMatcher::isIdentical(B);
|
||||
}
|
||||
|
||||
void emitPredicateOpcodes(MatchTable &Table,
|
||||
RuleMatcher &Rule) const override {
|
||||
Table << MatchTable::Opcode("GIM_CheckHasOneUse")
|
||||
<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
|
||||
<< MatchTable::LineBreak;
|
||||
}
|
||||
};
|
||||
|
||||
/// Generates code to check that a set of predicates and operands match for a
|
||||
/// particular instruction.
|
||||
///
|
||||
|
@ -207,7 +207,7 @@ static Error isTrivialOperatorNode(const TreePatternNode &N) {
|
||||
if (Predicate.isImmediatePattern())
|
||||
continue;
|
||||
|
||||
if (Predicate.hasNoUse())
|
||||
if (Predicate.hasNoUse() || Predicate.hasOneUse())
|
||||
continue;
|
||||
|
||||
if (Predicate.isNonExtLoad() || Predicate.isAnyExtLoad() ||
|
||||
@ -782,6 +782,10 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
|
||||
InsnMatcher.addPredicate<NoUsePredicateMatcher>();
|
||||
HasAddedBuiltinMatcher = true;
|
||||
}
|
||||
if (Predicate.hasOneUse()) {
|
||||
InsnMatcher.addPredicate<OneUsePredicateMatcher>();
|
||||
HasAddedBuiltinMatcher = true;
|
||||
}
|
||||
|
||||
if (Predicate.hasGISelPredicateCode()) {
|
||||
if (Predicate.usesOperands()) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user