/// - InsnID - Instruction ID
/// - The predicate to test
GIM_CheckAPFloatImmPredicate,
+ /// Check an immediate predicate on the specified instruction
+ /// - InsnID - Instruction ID
+ /// - OpIdx - Operand index
+ /// - The predicate to test
+ GIM_CheckImmOperandPredicate,
/// Check a memory operation has the specified atomic ordering.
/// - InsnID - Instruction ID
/// - Ordering - The AtomicOrdering value
}
break;
}
- case GIM_CheckI64ImmPredicate: {
+ case GIM_CheckI64ImmPredicate:
+ case GIM_CheckImmOperandPredicate: {
int64_t InsnID = MatchTable[CurrentIdx++];
+ int64_t OpIdx = MatcherOpcode == GIM_CheckImmOperandPredicate
+ ? MatchTable[CurrentIdx++]
+ : 1;
int64_t Predicate = MatchTable[CurrentIdx++];
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
- dbgs()
- << CurrentIdx << ": GIM_CheckI64ImmPredicate(MIs["
- << InsnID << "], Predicate=" << Predicate << ")\n");
+ dbgs() << CurrentIdx << ": GIM_CheckImmPredicate(MIs["
+ << InsnID << "]->getOperand(" << OpIdx
+ << "), Predicate=" << Predicate << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
- assert(State.MIs[InsnID]->getOpcode() == TargetOpcode::G_CONSTANT &&
- "Expected G_CONSTANT");
+ assert((State.MIs[InsnID]->getOperand(OpIdx).isImm() ||
+ State.MIs[InsnID]->getOperand(OpIdx).isCImm()) &&
+ "Expected immediate operand");
assert(Predicate > GIPFP_I64_Invalid && "Expected a valid predicate");
int64_t Value = 0;
- if (State.MIs[InsnID]->getOperand(1).isCImm())
- Value = State.MIs[InsnID]->getOperand(1).getCImm()->getSExtValue();
- else if (State.MIs[InsnID]->getOperand(1).isImm())
- Value = State.MIs[InsnID]->getOperand(1).getImm();
+ if (State.MIs[InsnID]->getOperand(OpIdx).isCImm())
+ Value = State.MIs[InsnID]->getOperand(OpIdx).getCImm()->getSExtValue();
+ else if (State.MIs[InsnID]->getOperand(OpIdx).isImm())
+ Value = State.MIs[InsnID]->getOperand(OpIdx).getImm();
else
llvm_unreachable("Expected Imm or CImm operand");
// G_INTTOPTR - SelectionDAG has no equivalent.
// G_PTRTOINT - SelectionDAG has no equivalent.
def : GINodeEquiv<G_CONSTANT, imm>;
+// timm must not be materialized and therefore has no GlobalISel equivalent
def : GINodeEquiv<G_FCONSTANT, fpimm>;
def : GINodeEquiv<G_IMPLICIT_DEF, undef>;
def : GINodeEquiv<G_FRAME_INDEX, frameindex>;
--- /dev/null
+// RUN: llvm-tblgen -gen-global-isel -optimize-match-table=false -I %p/Common -I %p/../../include %s -o - < %s | FileCheck -check-prefix=GISEL %s
+
+include "llvm/Target/Target.td"
+include "GlobalISelEmitterCommon.td"
+
+let TargetPrefix = "mytarget" in {
+def int_mytarget_sleep0 : Intrinsic<[], [llvm_i32_ty], [ImmArg<ArgIndex<0>>]>;
+}
+
+// GISEL: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS,
+// GISEL-NEXT: // MIs[0] Operand 0
+// GISEL-NEXT: GIM_CheckIntrinsicID, /*MI*/0, /*Op*/0, Intrinsic::mytarget_sleep0,
+// GISEL-NEXT: // MIs[0] src
+// GISEL-NEXT: GIM_CheckIsImm, /*MI*/0, /*Op*/1,
+// GISEL-NEXT: GIM_CheckImmOperandPredicate, /*MI*/0, /*MO*/1, /*Predicate*/GIPFP_I64_Predicate_tuimm9,
+// GISEL-NEXT: // (intrinsic_void {{[0-9]+}}:{ *:[iPTR] }, (timm:{ *:[i32] })<<P:Predicate_tuimm9>>:$src) => (SLEEP0 (timm:{ *:[i32] }):$src)
+// GISEL-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::SLEEP0,
+// GISEL-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src
+def tuimm9 : TImmLeaf<i32, [{ return isUInt<9>(Imm); }]>;
+def SLEEP0 : I<(outs), (ins i32imm:$src),
+ [(int_mytarget_sleep0 tuimm9:$src)]
+>;
}
/// Get the opcode used to check this predicate.
-std::string getMatchOpcodeForPredicate(const TreePredicateFn &Predicate) {
+std::string getMatchOpcodeForImmPredicate(const TreePredicateFn &Predicate) {
return "GIM_Check" + Predicate.getImmTypeIdentifier().str() + "ImmPredicate";
}
}
};
+/// Generates code to check that this operand is an immediate whose value meets
+/// an immediate predicate.
+class OperandImmPredicateMatcher : public OperandPredicateMatcher {
+protected:
+ TreePredicateFn Predicate;
+
+public:
+ OperandImmPredicateMatcher(unsigned InsnVarID, unsigned OpIdx,
+ const TreePredicateFn &Predicate)
+ : OperandPredicateMatcher(IPM_ImmPredicate, InsnVarID, OpIdx),
+ Predicate(Predicate) {}
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return OperandPredicateMatcher::isIdentical(B) &&
+ Predicate.getOrigPatFragRecord() ==
+ cast<OperandImmPredicateMatcher>(&B)
+ ->Predicate.getOrigPatFragRecord();
+ }
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_ImmPredicate;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override {
+ Table << MatchTable::Opcode("GIM_CheckImmOperandPredicate")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("MO") << MatchTable::IntValue(OpIdx)
+ << MatchTable::Comment("Predicate")
+ << MatchTable::NamedValue(getEnumNameForPredicate(Predicate))
+ << MatchTable::LineBreak;
+ }
+};
+
/// Generates code to check that a set of predicates match for a particular
/// operand.
class OperandMatcher : public PredicateListMatcher<OperandPredicateMatcher> {
void emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const override {
- Table << MatchTable::Opcode(getMatchOpcodeForPredicate(Predicate))
+ Table << MatchTable::Opcode(getMatchOpcodeForImmPredicate(Predicate))
<< MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
<< MatchTable::Comment("Predicate")
<< MatchTable::NamedValue(getEnumNameForPredicate(Predicate))
}
if (SrcChild->getOperator()->getName() == "timm") {
OM.addPredicate<ImmOperandMatcher>();
+
+ // Add predicates, if any
+ for (const TreePredicateCall &Call : SrcChild->getPredicateCalls()) {
+ const TreePredicateFn &Predicate = Call.Fn;
+
+ // Only handle immediate patterns for now
+ if (Predicate.isImmediatePattern()) {
+ OM.addPredicate<OperandImmPredicateMatcher>(Predicate);
+ }
+ }
+
return Error::success();
}
}