diff --git a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h --- a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -210,6 +210,11 @@ /// - OpIdx - Operand index /// - SizeInBits - The size of the pointer value in bits. GIM_CheckPointerToAny, + /// Check the size of a type + /// - InsnID - Instruction ID + /// - OpIdx - Operand index + /// - SizeInBits - The size of the type value in bits. + GIM_CheckTypeSize, /// Check the register bank for the specified operand /// - InsnID - Instruction ID /// - OpIdx - Operand index @@ -364,7 +369,8 @@ /// reading from a specific operand. /// - InsnID - Instruction ID to modify /// - OldInsnID - Instruction ID to get the matched operand from - /// - OpIdx - Operand index in OldInsnID the render function should read from.. + /// - OpIdx - Operand index in OldInsnID the render function should read + /// from.. /// - RendererFnID - Custom renderer function to call GIR_CustomOperandRenderer, diff --git a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h --- a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h @@ -643,6 +643,29 @@ break; } + case GIM_CheckTypeSize: { + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t OpIdx = MatchTable[CurrentIdx++]; + uint64_t SizeInBits = MatchTable[CurrentIdx++]; + + DEBUG_WITH_TYPE(TgtInstructionSelector::getName(), + dbgs() << CurrentIdx << ": GIM_CheckTypeSize(MIs[" + << InsnID << "]->getOperand(" << OpIdx + << "), SizeInBits=" << SizeInBits << ")\n"); + assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); + assert(SizeInBits != 0 && "SizeInBits Cannot be Zero"); + MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx); + const LLT Ty = MRI.getType(MO.getReg()); + + if (MO.isReg()) { + if (Ty.getSizeInBits() != SizeInBits) + if (handleReject() == RejectAndGiveUp) + return false; + } else if (handleReject() == RejectAndGiveUp) + return false; + + break; + } case GIM_RecordNamedOperand: { int64_t InsnID = MatchTable[CurrentIdx++]; int64_t OpIdx = MatchTable[CurrentIdx++]; diff --git a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td --- a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td +++ b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td @@ -39,6 +39,12 @@ // SelectionDAG has one setcc for all compares. This differentiates // for G_ICMP and G_FCMP. Instruction IfFloatingPoint = ?; + + // SelectionDAG uses add for both pointer and classic addition. + // GISel has G_PTR_ADD and G_ADD for those. + // This allows us to differentiate the opcodes based on the instruction's + // type. + Instruction IfPointerType = ?; } // These are defined in the same order as the G_* instructions. @@ -55,7 +61,6 @@ def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; -def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; @@ -157,6 +162,10 @@ def : GINodeEquiv; def : GINodeEquiv; +def : GINodeEquiv { + let IfPointerType = G_PTR_ADD; +} + // Broadly speaking G_LOAD is equivalent to ISD::LOAD but there are some // complications that tablegen must take care of. For example, Predicates such // as isSignExtLoad require that this is not a perfect 1:1 mapping since a diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td --- a/llvm/include/llvm/Target/TargetSelectionDAG.td +++ b/llvm/include/llvm/Target/TargetSelectionDAG.td @@ -1839,6 +1839,10 @@ list ResultInstrs = resultInstrs; list Predicates = []; // See class Instruction in Target.td. int AddedComplexity = 0; // See class Instruction in Target.td. + + // Whether pointers are allowed in place of sinilarly-sized integers. + // e.g. a 32 bit pointer can match against i32. + bit AllowPointerOperands = false; } // Pat - A simple (but common) form of a pattern, which produces a simple result diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp --- a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp @@ -3485,6 +3485,8 @@ case TargetOpcode::G_BUILD_VECTOR_TRUNC: return selectG_BUILD_VECTOR_TRUNC(I); case TargetOpcode::G_PTR_ADD: + if (selectImpl(I, *CoverageInfo)) + return true; return selectG_PTR_ADD(I); case TargetOpcode::G_IMPLICIT_DEF: return selectG_IMPLICIT_DEF(I); diff --git a/llvm/lib/Target/AMDGPU/SIInstructions.td b/llvm/lib/Target/AMDGPU/SIInstructions.td --- a/llvm/lib/Target/AMDGPU/SIInstructions.td +++ b/llvm/lib/Target/AMDGPU/SIInstructions.td @@ -10,9 +10,7 @@ // that are not yet supported remain commented out. //===----------------------------------------------------------------------===// -class GCNPat : Pat, GCNPredicateControl { - -} +class GCNPat : Pat, GCNPredicateControl; class UniformSextInreg : PatFrag< (ops node:$src), diff --git a/llvm/lib/Target/AMDGPU/VOP3Instructions.td b/llvm/lib/Target/AMDGPU/VOP3Instructions.td --- a/llvm/lib/Target/AMDGPU/VOP3Instructions.td +++ b/llvm/lib/Target/AMDGPU/VOP3Instructions.td @@ -452,8 +452,15 @@ // FIXME: There's no register bank verifier let GISelPredicateCode = [{ const int ConstantBusLimit = Subtarget->getConstantBusLimit(AMDGPU::V_ADD3_U32_e64); + int ConstantBusUses = 0; for (unsigned i = 0; i < 3; ++i) { + + // FIX: Somehow my changes made this predicate run before the + // Feature check, so it crashes without this. + if(!Operands[i] || !Operands[i]->isReg()) + return true; + const RegisterBank *RegBank = RBI.getRegBank(Operands[i]->getReg(), MRI, TRI); if (RegBank->getID() == AMDGPU::SGPRRegBankID) { if (++ConstantBusUses > ConstantBusLimit) @@ -587,15 +594,17 @@ def : Cvt_SR_F8_F32_Pat; } -class ThreeOp_i32_Pats : GCNPat < - // This matches (op2 (op1 i32:$src0, i32:$src1), i32:$src2) with conditions. - (ThreeOpFrag i32:$src0, i32:$src1, i32:$src2), - (inst VSrc_b32:$src0, VSrc_b32:$src1, VSrc_b32:$src2) ->; +class ThreeOp_i32_Pats + : GCNPat <(ThreeOpFrag i32:$src0, i32:$src1, i32:$src2), + (inst VSrc_b32:$src0, VSrc_b32:$src1, VSrc_b32:$src2)> { + let AllowPointerOperands = genPointerPat; +} def : ThreeOp_i32_Pats; def : ThreeOp_i32_Pats; -def : ThreeOp_i32_Pats; + +def : ThreeOp_i32_Pats; + def : ThreeOp_i32_Pats; def : ThreeOp_i32_Pats; def : ThreeOp_i32_Pats; diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-pattern-add3.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-pattern-add3.mir --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-pattern-add3.mir +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-pattern-add3.mir @@ -137,9 +137,8 @@ ; GFX9-NEXT: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr0 ; GFX9-NEXT: [[COPY1:%[0-9]+]]:vgpr_32 = COPY $vgpr1 ; GFX9-NEXT: [[COPY2:%[0-9]+]]:vgpr_32 = COPY $vgpr2 - ; GFX9-NEXT: [[V_ADD_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 [[COPY]], [[COPY1]], 0, implicit $exec - ; GFX9-NEXT: [[V_ADD_U32_e64_1:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 [[V_ADD_U32_e64_]], [[COPY2]], 0, implicit $exec - ; GFX9-NEXT: S_ENDPGM 0, implicit [[V_ADD_U32_e64_1]] + ; GFX9-NEXT: [[V_ADD3_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD3_U32_e64 [[COPY]], [[COPY1]], [[COPY2]], implicit $exec + ; GFX9-NEXT: S_ENDPGM 0, implicit [[V_ADD3_U32_e64_]] %0:vgpr(p3) = COPY $vgpr0 %1:vgpr(s32) = COPY $vgpr1 %2:vgpr(s32) = COPY $vgpr2 @@ -174,9 +173,8 @@ ; GFX9-NEXT: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr0 ; GFX9-NEXT: [[COPY1:%[0-9]+]]:vgpr_32 = COPY $vgpr1 ; GFX9-NEXT: [[COPY2:%[0-9]+]]:vgpr_32 = COPY $vgpr2 - ; GFX9-NEXT: [[V_ADD_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 [[COPY]], [[COPY1]], 0, implicit $exec - ; GFX9-NEXT: [[V_ADD_U32_e64_1:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 [[V_ADD_U32_e64_]], [[COPY2]], 0, implicit $exec - ; GFX9-NEXT: S_ENDPGM 0, implicit [[V_ADD_U32_e64_1]] + ; GFX9-NEXT: [[V_ADD3_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD3_U32_e64 [[COPY]], [[COPY1]], [[COPY2]], implicit $exec + ; GFX9-NEXT: S_ENDPGM 0, implicit [[V_ADD3_U32_e64_]] %0:vgpr(p5) = COPY $vgpr0 %1:vgpr(s32) = COPY $vgpr1 %2:vgpr(s32) = COPY $vgpr2 @@ -211,9 +209,8 @@ ; GFX9-NEXT: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr0 ; GFX9-NEXT: [[COPY1:%[0-9]+]]:vgpr_32 = COPY $vgpr1 ; GFX9-NEXT: [[COPY2:%[0-9]+]]:vgpr_32 = COPY $vgpr2 - ; GFX9-NEXT: [[V_ADD_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 [[COPY]], [[COPY1]], 0, implicit $exec - ; GFX9-NEXT: [[V_ADD_U32_e64_1:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 [[COPY2]], [[V_ADD_U32_e64_]], 0, implicit $exec - ; GFX9-NEXT: S_ENDPGM 0, implicit [[V_ADD_U32_e64_1]] + ; GFX9-NEXT: [[V_ADD3_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD3_U32_e64 [[COPY]], [[COPY1]], [[COPY2]], implicit $exec + ; GFX9-NEXT: S_ENDPGM 0, implicit [[V_ADD3_U32_e64_]] %0:vgpr(s32) = COPY $vgpr0 %1:vgpr(s32) = COPY $vgpr1 %2:vgpr(p3) = COPY $vgpr2 @@ -248,9 +245,8 @@ ; GFX9-NEXT: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr0 ; GFX9-NEXT: [[COPY1:%[0-9]+]]:vgpr_32 = COPY $vgpr1 ; GFX9-NEXT: [[COPY2:%[0-9]+]]:vgpr_32 = COPY $vgpr2 - ; GFX9-NEXT: [[V_ADD_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 [[COPY]], [[COPY1]], 0, implicit $exec - ; GFX9-NEXT: [[V_ADD_U32_e64_1:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 [[COPY2]], [[V_ADD_U32_e64_]], 0, implicit $exec - ; GFX9-NEXT: S_ENDPGM 0, implicit [[V_ADD_U32_e64_1]] + ; GFX9-NEXT: [[V_ADD3_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD3_U32_e64 [[COPY]], [[COPY1]], [[COPY2]], implicit $exec + ; GFX9-NEXT: S_ENDPGM 0, implicit [[V_ADD3_U32_e64_]] %0:vgpr(s32) = COPY $vgpr0 %1:vgpr(s32) = COPY $vgpr1 %2:vgpr(p5) = COPY $vgpr2 diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -1133,6 +1133,7 @@ OPM_LiteralInt, OPM_LLT, OPM_PointerToAny, + OPM_LLTSize, OPM_RegBank, OPM_MBB, OPM_RecordNamedOperand, @@ -1327,6 +1328,37 @@ } }; +/// Generates code to check that an operand's type is of a certain size. +class LLTSizeOperandMatcher : public OperandPredicateMatcher { +protected: + unsigned SizeInBits; + +public: + LLTSizeOperandMatcher(unsigned InsnVarID, unsigned OpIdx, unsigned SizeInBits) + : OperandPredicateMatcher(OPM_LLTSize, InsnVarID, OpIdx), + SizeInBits(SizeInBits) { + assert(SizeInBits != 0); + } + + static bool classof(const PredicateMatcher *P) { + return P->getKind() == OPM_LLTSize; + } + + bool isIdentical(const PredicateMatcher &B) const override { + return OperandPredicateMatcher::isIdentical(B) && + SizeInBits == cast(&B)->SizeInBits; + } + + void emitPredicateOpcodes(MatchTable &Table, + RuleMatcher &Rule) const override { + Table << MatchTable::Opcode("GIM_CheckTypeSize") + << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) + << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx) + << MatchTable::Comment("SizeInBits") + << MatchTable::IntValue(SizeInBits) << MatchTable::LineBreak; + } +}; + /// Generates code to record named operand in RecordedOperands list at StoreIdx. /// Predicates with 'let PredicateCodeUsesOperands = 1' get RecordedOperands as /// an argument to predicate's c++ code once all operands have been matched. @@ -1660,8 +1692,13 @@ InstructionMatcher &getInstructionMatcher() const { return Insn; } - Error addTypeCheckPredicate(const TypeSetByHwMode &VTy, - bool OperandIsAPointer); + enum OperandKind { + OK_NotPointer, + OK_Pointer, + OK_MaybePointer, + }; + + Error addTypeCheckPredicate(const TypeSetByHwMode &VTy, OperandKind OpKind); /// Emit MatchTable opcodes that test whether the instruction named in /// InsnVarID matches all the predicates and all the operands. @@ -1725,11 +1762,25 @@ }; Error OperandMatcher::addTypeCheckPredicate(const TypeSetByHwMode &VTy, - bool OperandIsAPointer) { + OperandKind OpKind) { if (!VTy.isMachineValueType()) return failedImport("unsupported typeset"); - if (VTy.getMachineValueType() == MVT::iPTR && OperandIsAPointer) { + bool UsePointerToAnyMatcher = false; + + switch (OpKind) { + case OK_NotPointer: + UsePointerToAnyMatcher = false; + break; + case OK_MaybePointer: + UsePointerToAnyMatcher |= VTy.getMachineValueType().isInteger(); + [[fallthrough]]; + case OK_Pointer: + UsePointerToAnyMatcher |= true; + break; + } + + if (UsePointerToAnyMatcher && VTy.getMachineValueType() == MVT::iPTR) { addPredicate(0); return Error::success(); } @@ -1738,9 +1789,13 @@ if (!OpTyOrNone) return failedImport("unsupported type"); - if (OperandIsAPointer) - addPredicate(OpTyOrNone->get().getSizeInBits()); - else if (VTy.isPointer()) + if (UsePointerToAnyMatcher) { + if (OpKind == OK_Pointer) + addPredicate( + OpTyOrNone->get().getSizeInBits()); + else + addPredicate(OpTyOrNone->get().getSizeInBits()); + } else if (VTy.isPointer()) addPredicate(LLT::pointer(VTy.getPtrAddrSpace(), OpTyOrNone->get().getSizeInBits())); else @@ -3609,19 +3664,22 @@ Record *findNodeEquiv(Record *N) const; const CodeGenInstruction *getEquivNode(Record &Equiv, - const TreePatternNode *N) const; + const TreePatternNode *N, + bool HasPointerOperands) const; Error importRulePredicates(RuleMatcher &M, ArrayRef Predicates); Expected createAndImportSelDAGMatcher(RuleMatcher &Rule, InstructionMatcher &InsnMatcher, - const TreePatternNode *Src, unsigned &TempOpIdx); + const TreePatternNode *Src, unsigned &TempOpIdx, + bool AllowsPointerOperands); Error importComplexPatternOperandMatcher(OperandMatcher &OM, Record *R, unsigned &TempOpIdx) const; Error importChildMatcher(RuleMatcher &Rule, InstructionMatcher &InsnMatcher, const TreePatternNode *SrcChild, bool OperandIsAPointer, bool OperandIsImmArg, - unsigned OpIdx, unsigned &TempOpIdx); + unsigned OpIdx, unsigned &TempOpIdx, + bool AllowsPointerOperands); Expected createAndImportInstructionRenderer( RuleMatcher &M, InstructionMatcher &InsnMatcher, @@ -3775,12 +3833,17 @@ } const CodeGenInstruction * -GlobalISelEmitter::getEquivNode(Record &Equiv, const TreePatternNode *N) const { +GlobalISelEmitter::getEquivNode(Record &Equiv, const TreePatternNode *N, + bool HasPointerOperands) const { if (N->getNumChildren() >= 1) { // setcc operation maps to two different G_* instructions based on the type. if (!Equiv.isValueUnset("IfFloatingPoint") && MVT(N->getChild(0)->getSimpleType(0)).isFloatingPoint()) return &Target.getInstruction(Equiv.getValueAsDef("IfFloatingPoint")); + + if (!Equiv.isValueUnset("IfPointerType") && HasPointerOperands) { + return &Target.getInstruction(Equiv.getValueAsDef("IfPointerType")); + } } for (const TreePredicateCall &Call : N->getPredicateCalls()) { @@ -3976,7 +4039,8 @@ Expected GlobalISelEmitter::createAndImportSelDAGMatcher( RuleMatcher &Rule, InstructionMatcher &InsnMatcher, - const TreePatternNode *Src, unsigned &TempOpIdx) { + const TreePatternNode *Src, unsigned &TempOpIdx, + bool AllowsPointerOperands) { Record *SrcGIEquivOrNull = nullptr; const CodeGenInstruction *SrcGIOrNull = nullptr; @@ -3997,10 +4061,24 @@ if (!SrcGIEquivOrNull) return failedImport("Pattern operator lacks an equivalent Instruction" + explainOperator(Src->getOperator())); - SrcGIOrNull = getEquivNode(*SrcGIEquivOrNull, Src); - // The operators look good: match the opcode - InsnMatcher.addPredicate(SrcGIOrNull); + SrcGIOrNull = + getEquivNode(*SrcGIEquivOrNull, Src, /*HasPointerOperands*/ false); + + // The operators look good: match the opcode. + // + // When AllowsPointerOperands is true, use the IfPointerAdd instruction + // as an alternative of the original one. + if (AllowsPointerOperands) + InsnMatcher.addPredicate( + ArrayRef{ + SrcGIOrNull, getEquivNode(*SrcGIEquivOrNull, Src, + /*HasPointerOperands*/ true)}); + else + InsnMatcher.addPredicate(SrcGIOrNull); + + // bool ptrAdd = (SrcGIOrNull->TheDef->getName() == "G_PTR_ADD"); + // assert(ptrAdd == (Rule.getOpcode() == "G_PTR_ADD")); } unsigned OpIdx = 0; @@ -4008,7 +4086,9 @@ // Results don't have a name unless they are the root node. The caller will // set the name if appropriate. OperandMatcher &OM = InsnMatcher.addOperand(OpIdx++, "", TempOpIdx); - if (auto Error = OM.addTypeCheckPredicate(VTy, false /* OperandIsAPointer */)) + if (auto Error = OM.addTypeCheckPredicate( + VTy, AllowsPointerOperands ? OperandMatcher::OK_MaybePointer + : OperandMatcher::OK_NotPointer)) return failedImport(toString(std::move(Error)) + " for result of Src pattern operator"); } @@ -4128,12 +4208,14 @@ TreePatternNode *PtrChild = Src->getChild(0); TreePatternNode *ValueChild = Src->getChild(1); - if (auto Error = importChildMatcher(Rule, InsnMatcher, PtrChild, true, - false, 1, TempOpIdx)) + if (auto Error = + importChildMatcher(Rule, InsnMatcher, PtrChild, true, false, 1, + TempOpIdx, AllowsPointerOperands)) return std::move(Error); - if (auto Error = importChildMatcher(Rule, InsnMatcher, ValueChild, false, - false, 0, TempOpIdx)) + if (auto Error = + importChildMatcher(Rule, InsnMatcher, ValueChild, false, false, 0, + TempOpIdx, AllowsPointerOperands)) return std::move(Error); return InsnMatcher; } @@ -4182,9 +4264,9 @@ OperandIsImmArg |= II->isParamImmArg(i - 1); } - if (auto Error = - importChildMatcher(Rule, InsnMatcher, SrcChild, OperandIsAPointer, - OperandIsImmArg, OpIdx++, TempOpIdx)) + if (auto Error = importChildMatcher( + Rule, InsnMatcher, SrcChild, OperandIsAPointer, OperandIsImmArg, + OpIdx++, TempOpIdx, AllowsPointerOperands)) return std::move(Error); } } @@ -4222,10 +4304,13 @@ return SrcChildName; } -Error GlobalISelEmitter::importChildMatcher( - RuleMatcher &Rule, InstructionMatcher &InsnMatcher, - const TreePatternNode *SrcChild, bool OperandIsAPointer, - bool OperandIsImmArg, unsigned OpIdx, unsigned &TempOpIdx) { +Error GlobalISelEmitter::importChildMatcher(RuleMatcher &Rule, + InstructionMatcher &InsnMatcher, + const TreePatternNode *SrcChild, + bool OperandIsAPointer, + bool OperandIsImmArg, + unsigned OpIdx, unsigned &TempOpIdx, + bool AllowsPointerOperands) { Record *PhysReg = nullptr; std::string SrcChildName = std::string(getSrcChildName(SrcChild, PhysReg)); @@ -4280,8 +4365,18 @@ // Immediate arguments have no meaningful type to check as they don't have // registers. if (!OperandIsImmArg) { - if (auto Error = - OM.addTypeCheckPredicate(ChildTypes.front(), OperandIsAPointer)) + OperandMatcher::OperandKind OpKind = OperandMatcher::OK_NotPointer; + + // AllowsPointerOperands > OperandIsAPointer + if (OperandIsAPointer) { + OpKind = OperandMatcher::OK_Pointer; + } + + if (AllowsPointerOperands) { + OpKind = OperandMatcher::OK_MaybePointer; + } + + if (auto Error = OM.addTypeCheckPredicate(ChildTypes.front(), OpKind)) return failedImport(toString(std::move(Error)) + " for Src operand (" + to_string(*SrcChild) + ")"); } @@ -4323,10 +4418,10 @@ // Map the node to a gMIR instruction. InstructionOperandMatcher &InsnOperand = **MaybeInsnOperand; auto InsnMatcherOrError = createAndImportSelDAGMatcher( - Rule, InsnOperand.getInsnMatcher(), SrcChild, TempOpIdx); + Rule, InsnOperand.getInsnMatcher(), SrcChild, TempOpIdx, + AllowsPointerOperands); if (auto Error = InsnMatcherOrError.takeError()) return Error; - return Error::success(); } @@ -4421,8 +4516,9 @@ // has to succeed. OperandMatcher &OM = InsnOperand.getInsnMatcher().addOperand(0, "", TempOpIdx); - if (auto Error = - OM.addTypeCheckPredicate(VTy, false /* OperandIsAPointer */)) + auto OpKind = AllowsPointerOperands ? OperandMatcher::OK_MaybePointer + : OperandMatcher::OK_NotPointer; + if (auto Error = OM.addTypeCheckPredicate(VTy, OpKind)) return failedImport(toString(std::move(Error)) + " for result of Src pattern operator"); @@ -5199,10 +5295,17 @@ // the capture accross rules. The downside is that it would // introduce a dependency between predicates (captures must happen // before their first use.) + + // FIXME: Instruction patterns seem to pass through here and they dont inherit + // from Pattern, so AllowPointerOperands isn't guaranteed to be defined. + bool AllowsPointerOperands = + P.getSrcRecord()->getValue("AllowPointerOperands") && + P.getSrcRecord()->getValueAsBit("AllowPointerOperands"); + InstructionMatcher &InsnMatcherTemp = M.addInstructionMatcher(Src->getName()); unsigned TempOpIdx = 0; - auto InsnMatcherOrError = - createAndImportSelDAGMatcher(M, InsnMatcherTemp, Src, TempOpIdx); + auto InsnMatcherOrError = createAndImportSelDAGMatcher( + M, InsnMatcherTemp, Src, TempOpIdx, AllowsPointerOperands); if (auto Error = InsnMatcherOrError.takeError()) return std::move(Error); InstructionMatcher &InsnMatcher = InsnMatcherOrError.get();