Index: llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h +++ llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h @@ -59,8 +59,8 @@ MI.getOperand(1).getReg(), MRI)) { unsigned DstReg = MI.getOperand(0).getReg(); LLT DstTy = MRI.getType(DstReg); - if (isInstUnsupported(TargetOpcode::G_AND, DstTy) || - isInstUnsupported(TargetOpcode::G_CONSTANT, DstTy)) + if (isInstUnsupported({TargetOpcode::G_AND, {DstTy}}) || + isInstUnsupported({TargetOpcode::G_CONSTANT, {DstTy}})) return false; DEBUG(dbgs() << ".. Combine MI: " << MI;); Builder.setInstr(MI); @@ -87,9 +87,9 @@ MI.getOperand(1).getReg(), MRI)) { unsigned DstReg = MI.getOperand(0).getReg(); LLT DstTy = MRI.getType(DstReg); - if (isInstUnsupported(TargetOpcode::G_SHL, DstTy) || - isInstUnsupported(TargetOpcode::G_ASHR, DstTy) || - isInstUnsupported(TargetOpcode::G_CONSTANT, DstTy)) + if (isInstUnsupported({TargetOpcode::G_SHL, {DstTy}}) || + isInstUnsupported({TargetOpcode::G_ASHR, {DstTy}}) || + isInstUnsupported({TargetOpcode::G_CONSTANT, {DstTy}})) return false; DEBUG(dbgs() << ".. Combine MI: " << MI;); Builder.setInstr(MI); @@ -121,7 +121,7 @@ MI.getOperand(1).getReg(), MRI)) { unsigned DstReg = MI.getOperand(0).getReg(); LLT DstTy = MRI.getType(DstReg); - if (isInstUnsupported(TargetOpcode::G_IMPLICIT_DEF, DstTy)) + if (isInstUnsupported({TargetOpcode::G_IMPLICIT_DEF, {DstTy}})) return false; DEBUG(dbgs() << ".. Combine EXT(IMPLICIT_DEF) " << MI;); Builder.setInstr(MI); @@ -277,10 +277,10 @@ /// Checks if the target legalizer info has specified anything about the /// instruction, or if unsupported. - bool isInstUnsupported(unsigned Opcode, const LLT &DstTy) const { - auto Action = LI.getAction({Opcode, 0, DstTy}); - return Action.first == LegalizerInfo::LegalizeAction::Unsupported || - Action.first == LegalizerInfo::LegalizeAction::NotFound; + bool isInstUnsupported(const LegalityQuery &Query) const { + auto Step = LI.getAction(Query); + return Step.Action == LegalizerInfo::LegalizeAction::Unsupported || + Step.Action == LegalizerInfo::LegalizeAction::NotFound; } }; Index: llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h +++ llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h @@ -51,6 +51,15 @@ } }; +/// The LegalityQuery object bundles together all the information that's needed +/// to decide whether a given operation is legal or not. +/// For efficiency, it doesn't make a copy of Types so care must be taken not +/// to free it before using the query. +struct LegalityQuery { + unsigned Opcode; + ArrayRef Types; +}; + class LegalizerInfo { public: enum LegalizeAction : std::uint8_t { @@ -100,6 +109,27 @@ NotFound, }; + /// The result of a query. It either indicates a final answer of Legal or + /// Unsupported or describes an action that must be taken to make an operation + /// more legal. + struct LegalizeActionStep { + /// The action to take or the final answer. + LegalizeAction Action; + /// If describing an action, the type index to change. Otherwise zero. + unsigned TypeIdx; + /// If describing an action, the new type for TypeIdx. Otherwise LLT{}. + LLT NewType; + + LegalizeActionStep(LegalizeAction Action, unsigned TypeIdx, + const LLT &NewType) + : Action(Action), TypeIdx(TypeIdx), NewType(NewType) {} + + bool operator==(const LegalizeActionStep &RHS) const { + return std::tie(Action, TypeIdx, NewType) == + std::tie(RHS.Action, RHS.TypeIdx, RHS.NewType); + } + }; + LegalizerInfo(); virtual ~LegalizerInfo() = default; @@ -259,22 +289,18 @@ LegalizeAction DecreaseAction, LegalizeAction IncreaseAction); - /// Determine what action should be taken to legalize the given generic - /// instruction opcode, type-index and type. Requires computeTables to have - /// been called. + /// Determine what action should be taken to legalize the described + /// instruction. Requires computeTables to have been called. /// - /// \returns a pair consisting of the kind of legalization that should be - /// performed and the destination type. - std::pair getAction(const InstrAspect &Aspect) const; + /// \returns a description of the next legalization step to perform. + LegalizeActionStep getAction(const LegalityQuery &Query) const; /// Determine what action should be taken to legalize the given generic /// instruction. /// - /// \returns a tuple consisting of the LegalizeAction that should be - /// performed, the type-index it should be performed on and the destination - /// type. - std::tuple - getAction(const MachineInstr &MI, const MachineRegisterInfo &MRI) const; + /// \returns a description of the next legalization step to perform. + LegalizeActionStep getAction(const MachineInstr &MI, + const MachineRegisterInfo &MRI) const; bool isLegal(const MachineInstr &MI, const MachineRegisterInfo &MRI) const; @@ -283,6 +309,15 @@ MachineIRBuilder &MIRBuilder) const; private: + /// Determine what action should be taken to legalize the given generic + /// instruction opcode, type-index and type. Requires computeTables to have + /// been called. + /// + /// \returns a pair consisting of the kind of legalization that should be + /// performed and the destination type. + std::pair + getAspectAction(const InstrAspect &Aspect) const; + /// The SizeAndActionsVec is a representation mapping between all natural /// numbers and an Action. The natural number represents the bit size of /// the InstrAspect. For example, for a target with native support for 32-bit Index: llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp =================================================================== --- llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -36,8 +36,8 @@ LegalizerHelper::legalizeInstrStep(MachineInstr &MI) { DEBUG(dbgs() << "Legalizing: "; MI.print(dbgs())); - auto Action = LI.getAction(MI, MRI); - switch (std::get<0>(Action)) { + auto Step = LI.getAction(MI, MRI); + switch (Step.Action) { case LegalizerInfo::Legal: DEBUG(dbgs() << ".. Already legal\n"); return AlreadyLegal; @@ -46,16 +46,16 @@ return libcall(MI); case LegalizerInfo::NarrowScalar: DEBUG(dbgs() << ".. Narrow scalar\n"); - return narrowScalar(MI, std::get<1>(Action), std::get<2>(Action)); + return narrowScalar(MI, Step.TypeIdx, Step.NewType); case LegalizerInfo::WidenScalar: DEBUG(dbgs() << ".. Widen scalar\n"); - return widenScalar(MI, std::get<1>(Action), std::get<2>(Action)); + return widenScalar(MI, Step.TypeIdx, Step.NewType); case LegalizerInfo::Lower: DEBUG(dbgs() << ".. Lower\n"); - return lower(MI, std::get<1>(Action), std::get<2>(Action)); + return lower(MI, Step.TypeIdx, Step.NewType); case LegalizerInfo::FewerElements: DEBUG(dbgs() << ".. Reduce number of elements\n"); - return fewerElementsVector(MI, std::get<1>(Action), std::get<2>(Action)); + return fewerElementsVector(MI, Step.TypeIdx, Step.NewType); case LegalizerInfo::Custom: DEBUG(dbgs() << ".. Custom legalization\n"); return LI.legalizeCustom(MI, MRI, MIRBuilder) ? Legalized @@ -924,7 +924,7 @@ // Lower (G_FSUB LHS, RHS) to (G_FADD LHS, (G_FNEG RHS)). // First, check if G_FNEG is marked as Lower. If so, we may // end up with an infinite loop as G_FSUB is used to legalize G_FNEG. - if (LI.getAction({G_FNEG, Ty}).first == LegalizerInfo::Lower) + if (LI.getAction({G_FNEG, {Ty}}).Action == LegalizerInfo::Lower) return UnableToLegalize; unsigned Res = MI.getOperand(0).getReg(); unsigned LHS = MI.getOperand(1).getReg(); Index: llvm/trunk/lib/CodeGen/GlobalISel/LegalizerInfo.cpp =================================================================== --- llvm/trunk/lib/CodeGen/GlobalISel/LegalizerInfo.cpp +++ llvm/trunk/lib/CodeGen/GlobalISel/LegalizerInfo.cpp @@ -163,7 +163,7 @@ // we have any hope of doing well with something like <13 x i3>. Even the common // cases should do better than what we have now. std::pair -LegalizerInfo::getAction(const InstrAspect &Aspect) const { +LegalizerInfo::getAspectAction(const InstrAspect &Aspect) const { assert(TablesInitialized && "backend forgot to call computeTables"); // These *have* to be implemented for now, they're the fundamental basis of // how everything else is transformed. @@ -186,9 +186,20 @@ return MRI.getType(MI.getOperand(OpIdx).getReg()); } -std::tuple +LegalizerInfo::LegalizeActionStep +LegalizerInfo::getAction(const LegalityQuery &Query) const { + for (unsigned i = 0; i < Query.Types.size(); ++i) { + auto Action = getAspectAction({Query.Opcode, i, Query.Types[i]}); + if (Action.first != Legal) + return {Action.first, i, Action.second}; + } + return {Legal, 0, LLT{}}; +} + +LegalizerInfo::LegalizeActionStep LegalizerInfo::getAction(const MachineInstr &MI, const MachineRegisterInfo &MRI) const { + SmallVector Types; SmallBitVector SeenTypes(8); const MCOperandInfo *OpInfo = MI.getDesc().OpInfo; // FIXME: probably we'll need to cache the results here somehow? @@ -205,16 +216,14 @@ SeenTypes.set(TypeIdx); LLT Ty = getTypeFromTypeIdx(MI, MRI, i, TypeIdx); - auto Action = getAction({MI.getOpcode(), TypeIdx, Ty}); - if (Action.first != Legal) - return std::make_tuple(Action.first, TypeIdx, Action.second); + Types.push_back(Ty); } - return std::make_tuple(Legal, 0, LLT{}); + return getAction({MI.getOpcode(), Types}); } bool LegalizerInfo::isLegal(const MachineInstr &MI, const MachineRegisterInfo &MRI) const { - return std::get<0>(getAction(MI, MRI)) == Legal; + return getAction(MI, MRI).Action == Legal; } bool LegalizerInfo::legalizeCustom(MachineInstr &MI, MachineRegisterInfo &MRI, Index: llvm/trunk/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp =================================================================== --- llvm/trunk/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp +++ llvm/trunk/unittests/CodeGen/GlobalISel/LegalizerInfoTest.cpp @@ -60,29 +60,29 @@ for (unsigned opcode : {G_ADD, G_SUB}) { // Check we infer the correct types and actually do what we're told. - ASSERT_EQ(L.getAction({opcode, LLT::scalar(8)}), - std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32))); - ASSERT_EQ(L.getAction({opcode, LLT::scalar(16)}), - std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32))); - ASSERT_EQ(L.getAction({opcode, LLT::scalar(32)}), - std::make_pair(LegalizerInfo::Legal, LLT::scalar(32))); - ASSERT_EQ(L.getAction({opcode, LLT::scalar(64)}), - std::make_pair(LegalizerInfo::Legal, LLT::scalar(64))); + ASSERT_EQ(L.getAction({opcode, {LLT::scalar(8)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::WidenScalar, 0, LLT::scalar(32))); + ASSERT_EQ(L.getAction({opcode, {LLT::scalar(16)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::WidenScalar, 0, LLT::scalar(32))); + ASSERT_EQ(L.getAction({opcode, {LLT::scalar(32)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::Legal, 0, LLT{})); + ASSERT_EQ(L.getAction({opcode, {LLT::scalar(64)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::Legal, 0, LLT{})); // Make sure the default for over-sized types applies. - ASSERT_EQ(L.getAction({opcode, LLT::scalar(128)}), - std::make_pair(LegalizerInfo::NarrowScalar, LLT::scalar(64))); + ASSERT_EQ(L.getAction({opcode, {LLT::scalar(128)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::NarrowScalar, 0, LLT::scalar(64))); // Make sure we also handle unusual sizes - ASSERT_EQ(L.getAction({opcode, LLT::scalar(1)}), - std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32))); - ASSERT_EQ(L.getAction({opcode, LLT::scalar(31)}), - std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32))); - ASSERT_EQ(L.getAction({opcode, LLT::scalar(33)}), - std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(64))); - ASSERT_EQ(L.getAction({opcode, LLT::scalar(63)}), - std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(64))); - ASSERT_EQ(L.getAction({opcode, LLT::scalar(65)}), - std::make_pair(LegalizerInfo::NarrowScalar, LLT::scalar(64))); + ASSERT_EQ(L.getAction({opcode, {LLT::scalar(1)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::WidenScalar, 0, LLT::scalar(32))); + ASSERT_EQ(L.getAction({opcode, {LLT::scalar(31)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::WidenScalar, 0, LLT::scalar(32))); + ASSERT_EQ(L.getAction({opcode, {LLT::scalar(33)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::WidenScalar, 0, LLT::scalar(64))); + ASSERT_EQ(L.getAction({opcode, {LLT::scalar(63)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::WidenScalar, 0, LLT::scalar(64))); + ASSERT_EQ(L.getAction({opcode, {LLT::scalar(65)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::NarrowScalar, 0, LLT::scalar(64))); } } @@ -106,19 +106,19 @@ // Check we infer the correct types and actually do what we're told for some // simple cases. - ASSERT_EQ(L.getAction({G_ADD, LLT::vector(8, 8)}), - std::make_pair(LegalizerInfo::Legal, LLT::vector(8, 8))); - ASSERT_EQ(L.getAction({G_ADD, LLT::vector(8, 7)}), - std::make_pair(LegalizerInfo::WidenScalar, LLT::vector(8, 8))); - ASSERT_EQ(L.getAction({G_ADD, LLT::vector(2, 8)}), - std::make_pair(LegalizerInfo::MoreElements, LLT::vector(8, 8))); - ASSERT_EQ(L.getAction({G_ADD, LLT::vector(8, 32)}), - std::make_pair(LegalizerInfo::FewerElements, LLT::vector(4, 32))); + ASSERT_EQ(L.getAction({G_ADD, {LLT::vector(8, 8)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::Legal, 0, LLT{})); + ASSERT_EQ(L.getAction({G_ADD, {LLT::vector(8, 7)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::WidenScalar, 0, LLT::vector(8, 8))); + ASSERT_EQ(L.getAction({G_ADD, {LLT::vector(2, 8)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::MoreElements, 0, LLT::vector(8, 8))); + ASSERT_EQ(L.getAction({G_ADD, {LLT::vector(8, 32)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::FewerElements, 0, LLT::vector(4, 32))); // Check a few non-power-of-2 sizes: - ASSERT_EQ(L.getAction({G_ADD, LLT::vector(3, 3)}), - std::make_pair(LegalizerInfo::WidenScalar, LLT::vector(3, 8))); - ASSERT_EQ(L.getAction({G_ADD, LLT::vector(3, 8)}), - std::make_pair(LegalizerInfo::MoreElements, LLT::vector(8, 8))); + ASSERT_EQ(L.getAction({G_ADD, {LLT::vector(3, 3)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::WidenScalar, 0, LLT::vector(3, 8))); + ASSERT_EQ(L.getAction({G_ADD, {LLT::vector(3, 8)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::MoreElements, 0, LLT::vector(8, 8))); } TEST(LegalizerInfoTest, MultipleTypes) { @@ -137,15 +137,16 @@ L.computeTables(); // Check we infer the correct types and actually do what we're told. - ASSERT_EQ(L.getAction({G_PTRTOINT, 0, s64}), - std::make_pair(LegalizerInfo::Legal, s64)); - ASSERT_EQ(L.getAction({G_PTRTOINT, 1, p0}), - std::make_pair(LegalizerInfo::Legal, p0)); + ASSERT_EQ(L.getAction({G_PTRTOINT, {s64, p0}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::Legal, 0, LLT{})); + // Make sure we also handle unusual sizes - ASSERT_EQ(L.getAction({G_PTRTOINT, 0, LLT::scalar(65)}), - std::make_pair(LegalizerInfo::NarrowScalar, s64)); - ASSERT_EQ(L.getAction({G_PTRTOINT, 1, LLT::pointer(0, 32)}), - std::make_pair(LegalizerInfo::Unsupported, LLT::pointer(0, 32))); + ASSERT_EQ( + L.getAction({G_PTRTOINT, {LLT::scalar(65), s64}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::NarrowScalar, 0, s64)); + ASSERT_EQ( + L.getAction({G_PTRTOINT, {s64, LLT::pointer(0, 32)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::Unsupported, 1, LLT::pointer(0, 32))); } TEST(LegalizerInfoTest, MultipleSteps) { @@ -161,10 +162,10 @@ L.computeTables(); - ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(16)}), - std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32))); - ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(32)}), - std::make_pair(LegalizerInfo::Lower, LLT::scalar(32))); + ASSERT_EQ(L.getAction({G_UREM, {LLT::scalar(16)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::WidenScalar, 0, LLT::scalar(32))); + ASSERT_EQ(L.getAction({G_UREM, {LLT::scalar(32)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::Lower, 0, LLT::scalar(32))); } TEST(LegalizerInfoTest, SizeChangeStrategy) { @@ -179,20 +180,20 @@ // Check we infer the correct types and actually do what we're told. for (unsigned Size : {1, 8, 16, 32}) { - ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(Size)}), - std::make_pair(LegalizerInfo::Legal, LLT::scalar(Size))); + ASSERT_EQ(L.getAction({G_UREM, {LLT::scalar(Size)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::Legal, 0, LLT{})); } - ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(2)}), - std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(8))); - ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(7)}), - std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(8))); - ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(9)}), - std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(16))); - ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(17)}), - std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32))); - ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(31)}), - std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32))); - ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(33)}), - std::make_pair(LegalizerInfo::Unsupported, LLT::scalar(33))); + ASSERT_EQ(L.getAction({G_UREM, {LLT::scalar(2)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::WidenScalar, 0, LLT::scalar(8))); + ASSERT_EQ(L.getAction({G_UREM, {LLT::scalar(7)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::WidenScalar, 0, LLT::scalar(8))); + ASSERT_EQ(L.getAction({G_UREM, {LLT::scalar(9)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::WidenScalar, 0, LLT::scalar(16))); + ASSERT_EQ(L.getAction({G_UREM, {LLT::scalar(17)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::WidenScalar, 0, LLT::scalar(32))); + ASSERT_EQ(L.getAction({G_UREM, {LLT::scalar(31)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::WidenScalar, 0, LLT::scalar(32))); + ASSERT_EQ(L.getAction({G_UREM, {LLT::scalar(33)}}), + LegalizerInfo::LegalizeActionStep(LegalizerInfo::Unsupported, 0, LLT::scalar(33))); } }