Index: include/llvm/CodeGen/GlobalISel/LegalizerInfo.h =================================================================== --- include/llvm/CodeGen/GlobalISel/LegalizerInfo.h +++ include/llvm/CodeGen/GlobalISel/LegalizerInfo.h @@ -19,6 +19,7 @@ #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/TargetOpcodes.h" @@ -37,6 +38,7 @@ class MachineInstr; class MachineIRBuilder; class MachineRegisterInfo; +class MCInstrInfo; namespace LegalizeActions { enum LegalizeAction : std::uint8_t { @@ -253,6 +255,33 @@ bool IsAliasedByAnother; SmallVector Rules; +#ifndef NDEBUG + /// If bit I is set, this rule set contains a rule that may handle (predicate + /// or perform an action upon (or both)) the type index I. The uncertainty + /// comes from free-form rules executing user-provided lambda functions. We + /// conservatively assume such rules do the right thing and cover all type + /// indices. The bitset is intentionally 1 bit wider than it absolutely needs + /// to be to distinguish such cases from the cases where all type indices are + /// individually handled. + SmallBitVector TypeIdxsCovered{MCOI::OPERAND_LAST_GENERIC - + MCOI::OPERAND_FIRST_GENERIC + 2}; +#endif + + unsigned typeIdx(unsigned TypeIdx) { + assert(TypeIdx <= + (MCOI::OPERAND_LAST_GENERIC - MCOI::OPERAND_FIRST_GENERIC) && + "Type Index is out of bounds"); +#ifndef NDEBUG + TypeIdxsCovered.set(TypeIdx); +#endif + return TypeIdx; + } + void markAllTypeIdxsAsCovered() { +#ifndef NDEBUG + TypeIdxsCovered.set(); +#endif + } + void add(const LegalizeRule &Rule) { assert(AliasOf == 0 && "RuleSet is aliased, change the representative opcode instead"); @@ -280,7 +309,7 @@ LegalizeRuleSet &actionFor(LegalizeAction Action, std::initializer_list Types) { using namespace LegalityPredicates; - return actionIf(Action, typeInSet(0, Types)); + return actionIf(Action, typeInSet(typeIdx(0), Types)); } /// Use the given action when type index 0 is any type in the given list. /// Action should be an action that requires mutation. @@ -288,7 +317,7 @@ std::initializer_list Types, LegalizeMutation Mutation) { using namespace LegalityPredicates; - return actionIf(Action, typeInSet(0, Types), Mutation); + return actionIf(Action, typeInSet(typeIdx(0), Types), Mutation); } /// Use the given action when type indexes 0 and 1 is any type pair in the /// given list. @@ -296,7 +325,7 @@ LegalizeRuleSet &actionFor(LegalizeAction Action, std::initializer_list> Types) { using namespace LegalityPredicates; - return actionIf(Action, typePairInSet(0, 1, Types)); + return actionIf(Action, typePairInSet(typeIdx(0), typeIdx(1), Types)); } /// Use the given action when type indexes 0 and 1 is any type pair in the /// given list. @@ -305,7 +334,8 @@ std::initializer_list> Types, LegalizeMutation Mutation) { using namespace LegalityPredicates; - return actionIf(Action, typePairInSet(0, 1, Types), Mutation); + return actionIf(Action, typePairInSet(typeIdx(0), typeIdx(1), Types), + Mutation); } /// Use the given action when type indexes 0 and 1 are both in the given list. /// That is, the type pair is in the cartesian product of the list. @@ -313,7 +343,8 @@ LegalizeRuleSet &actionForCartesianProduct(LegalizeAction Action, std::initializer_list Types) { using namespace LegalityPredicates; - return actionIf(Action, all(typeInSet(0, Types), typeInSet(1, Types))); + return actionIf(Action, all(typeInSet(typeIdx(0), Types), + typeInSet(typeIdx(1), Types))); } /// Use the given action when type indexes 0 and 1 are both in their /// respective lists. @@ -324,7 +355,20 @@ std::initializer_list Types0, std::initializer_list Types1) { using namespace LegalityPredicates; - return actionIf(Action, all(typeInSet(0, Types0), typeInSet(1, Types1))); + return actionIf(Action, all(typeInSet(typeIdx(0), Types0), + typeInSet(typeIdx(1), Types1))); + } + /// Use the given action when type indexes 0, 1, and 2 are all in their + /// respective lists. + /// That is, the type triple is in the cartesian product of the lists + /// Action should not be an action that requires mutation. + LegalizeRuleSet &actionForCartesianProduct( + LegalizeAction Action, std::initializer_list Types0, + std::initializer_list Types1, std::initializer_list Types2) { + using namespace LegalityPredicates; + return actionIf(Action, all(typeInSet(typeIdx(0), Types0), + all(typeInSet(typeIdx(1), Types1), + typeInSet(typeIdx(2), Types2)))); } public: @@ -342,6 +386,9 @@ /// The instruction is legal if predicate is true. LegalizeRuleSet &legalIf(LegalityPredicate Predicate) { + // We have no choice but conservatively assume that the free-form + // user-provided Predicate properly handles all type indices: + markAllTypeIdxsAsCovered(); return actionIf(LegalizeAction::Legal, Predicate); } /// The instruction is legal when type index 0 is any type in the given list. @@ -360,7 +407,7 @@ TypesAndMemSize) { return actionIf(LegalizeAction::Legal, LegalityPredicates::typePairAndMemSizeInSet( - 0, 1, /*MMOIdx*/ 0, TypesAndMemSize)); + typeIdx(0), typeIdx(1), /*MMOIdx*/ 0, TypesAndMemSize)); } /// The instruction is legal when type indexes 0 and 1 are both in the given /// list. That is, the type pair is in the cartesian product of the list. @@ -377,17 +424,26 @@ /// The instruction is lowered. LegalizeRuleSet &lower() { using namespace LegalizeMutations; + // We have no choice but conservatively assume that predicate-less lowering + // properly handles all type indices by design: + markAllTypeIdxsAsCovered(); return actionIf(LegalizeAction::Lower, always); } /// The instruction is lowered if predicate is true. Keep type index 0 as the /// same type. LegalizeRuleSet &lowerIf(LegalityPredicate Predicate) { using namespace LegalizeMutations; + // We have no choice but conservatively assume that lowering with a + // free-form user provided Predicate properly handles all type indices: + markAllTypeIdxsAsCovered(); return actionIf(LegalizeAction::Lower, Predicate); } /// The instruction is lowered if predicate is true. LegalizeRuleSet &lowerIf(LegalityPredicate Predicate, LegalizeMutation Mutation) { + // We have no choice but conservatively assume that lowering with a + // free-form user provided Predicate properly handles all type indices: + markAllTypeIdxsAsCovered(); return actionIf(LegalizeAction::Lower, Predicate, Mutation); } /// The instruction is lowered when type index 0 is any type in the given @@ -414,9 +470,28 @@ LegalizeMutation Mutation) { return actionFor(LegalizeAction::Lower, Types, Mutation); } + /// The instruction is lowered when type indexes 0 and 1 are both in their + /// respective lists. + LegalizeRuleSet &lowerForCartesianProduct(std::initializer_list Types0, + std::initializer_list Types1) { + using namespace LegalityPredicates; + return actionForCartesianProduct(LegalizeAction::Lower, Types0, Types1); + } + /// The instruction is lowered when when type indexes 0, 1, and 2 are all in + /// their respective lists. + LegalizeRuleSet &lowerForCartesianProduct(std::initializer_list Types0, + std::initializer_list Types1, + std::initializer_list Types2) { + using namespace LegalityPredicates; + return actionForCartesianProduct(LegalizeAction::Lower, Types0, Types1, + Types2); + } /// Like legalIf, but for the Libcall action. LegalizeRuleSet &libcallIf(LegalityPredicate Predicate) { + // We have no choice but conservatively assume that a libcall with a + // free-form user provided Predicate properly handles all type indices: + markAllTypeIdxsAsCovered(); return actionIf(LegalizeAction::Libcall, Predicate); } LegalizeRuleSet &libcallFor(std::initializer_list Types) { @@ -440,12 +515,18 @@ /// true. LegalizeRuleSet &widenScalarIf(LegalityPredicate Predicate, LegalizeMutation Mutation) { + // We have no choice but conservatively assume that an action with a + // free-form user provided Predicate properly handles all type indices: + markAllTypeIdxsAsCovered(); return actionIf(LegalizeAction::WidenScalar, Predicate, Mutation); } /// Narrow the scalar to the one selected by the mutation if the predicate is /// true. LegalizeRuleSet &narrowScalarIf(LegalityPredicate Predicate, LegalizeMutation Mutation) { + // We have no choice but conservatively assume that an action with a + // free-form user provided Predicate properly handles all type indices: + markAllTypeIdxsAsCovered(); return actionIf(LegalizeAction::NarrowScalar, Predicate, Mutation); } @@ -453,12 +534,18 @@ /// predicate is true. LegalizeRuleSet &moreElementsIf(LegalityPredicate Predicate, LegalizeMutation Mutation) { + // We have no choice but conservatively assume that an action with a + // free-form user provided Predicate properly handles all type indices: + markAllTypeIdxsAsCovered(); return actionIf(LegalizeAction::MoreElements, Predicate, Mutation); } /// Remove elements to reach the type selected by the mutation if the /// predicate is true. LegalizeRuleSet &fewerElementsIf(LegalityPredicate Predicate, LegalizeMutation Mutation) { + // We have no choice but conservatively assume that an action with a + // free-form user provided Predicate properly handles all type indices: + markAllTypeIdxsAsCovered(); return actionIf(LegalizeAction::FewerElements, Predicate, Mutation); } @@ -475,6 +562,9 @@ } LegalizeRuleSet &customIf(LegalityPredicate Predicate) { + // We have no choice but conservatively assume that a custom action with a + // free-form user provided Predicate properly handles all type indices: + markAllTypeIdxsAsCovered(); return actionIf(LegalizeAction::Custom, Predicate); } LegalizeRuleSet &customFor(std::initializer_list Types) { @@ -494,13 +584,14 @@ LegalizeRuleSet &widenScalarToNextPow2(unsigned TypeIdx, unsigned MinSize = 0) { using namespace LegalityPredicates; - return actionIf(LegalizeAction::WidenScalar, sizeNotPow2(TypeIdx), + return actionIf(LegalizeAction::WidenScalar, sizeNotPow2(typeIdx(TypeIdx)), LegalizeMutations::widenScalarToNextPow2(TypeIdx, MinSize)); } LegalizeRuleSet &narrowScalar(unsigned TypeIdx, LegalizeMutation Mutation) { using namespace LegalityPredicates; - return actionIf(LegalizeAction::NarrowScalar, isScalar(TypeIdx), Mutation); + return actionIf(LegalizeAction::NarrowScalar, isScalar(typeIdx(TypeIdx)), + Mutation); } /// Ensure the scalar is at least as wide as Ty. @@ -509,7 +600,7 @@ using namespace LegalizeMutations; return actionIf(LegalizeAction::WidenScalar, narrowerThan(TypeIdx, Ty.getSizeInBits()), - changeTo(TypeIdx, Ty)); + changeTo(typeIdx(TypeIdx), Ty)); } /// Ensure the scalar is at most as wide as Ty. @@ -518,7 +609,7 @@ using namespace LegalizeMutations; return actionIf(LegalizeAction::NarrowScalar, widerThan(TypeIdx, Ty.getSizeInBits()), - changeTo(TypeIdx, Ty)); + changeTo(typeIdx(TypeIdx), Ty)); } /// Conditionally limit the maximum size of the scalar. @@ -533,7 +624,7 @@ return widerThan(TypeIdx, Ty.getSizeInBits()) && Predicate(Query); }, - changeTo(TypeIdx, Ty)); + changeTo(typeIdx(TypeIdx), Ty)); } /// Limit the range of scalar sizes to MinTy and MaxTy. @@ -548,13 +639,16 @@ /// two. LegalizeRuleSet &moreElementsToNextPow2(unsigned TypeIdx) { using namespace LegalityPredicates; - return actionIf(LegalizeAction::MoreElements, numElementsNotPow2(TypeIdx), + return actionIf(LegalizeAction::MoreElements, + numElementsNotPow2(typeIdx(TypeIdx)), LegalizeMutations::moreElementsToNextPow2(TypeIdx)); } /// Limit the number of elements in EltTy vectors to at least MinElements. LegalizeRuleSet &clampMinNumElements(unsigned TypeIdx, const LLT &EltTy, unsigned MinElements) { + // Mark the type index as covered: + typeIdx(TypeIdx); return actionIf( LegalizeAction::MoreElements, [=](const LegalityQuery &Query) { @@ -571,6 +665,8 @@ /// Limit the number of elements in EltTy vectors to at most MaxElements. LegalizeRuleSet &clampMaxNumElements(unsigned TypeIdx, const LLT &EltTy, unsigned MaxElements) { + // Mark the type index as covered: + typeIdx(TypeIdx); return actionIf( LegalizeAction::FewerElements, [=](const LegalityQuery &Query) { @@ -607,6 +703,11 @@ return *this; } + /// Check if there is no type index which is obviously not handled by the + /// LegalizeRuleSet in any way at all. + /// \pre Type indices of the opcode form a dense [0, \p NumTypeIdxs) set. + bool verifyTypeIdxsCoverage(unsigned NumTypeIdxs) const; + /// Apply the ruleset to the given LegalityQuery. LegalizeActionStep apply(const LegalityQuery &Query) const; }; @@ -624,6 +725,10 @@ /// before any query is made or incorrect results may be returned. void computeTables(); + /// Perform simple self-diagnostic and assert if there is anything obviously + /// wrong with the actions set up. + void verify(const MCInstrInfo &MII) const; + static bool needsLegalizingToDifferentSize(const LegalizeAction Action) { using namespace LegalizeActions; switch (Action) { Index: lib/CodeGen/GlobalISel/LegalizerInfo.cpp =================================================================== --- lib/CodeGen/GlobalISel/LegalizerInfo.cpp +++ lib/CodeGen/GlobalISel/LegalizerInfo.cpp @@ -24,6 +24,7 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/MC/MCInstrDesc.h" +#include "llvm/MC/MCInstrInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LowLevelTypeImpl.h" @@ -83,6 +84,27 @@ return {LegalizeAction::Unsupported, 0, LLT{}}; } +bool LegalizeRuleSet::verifyTypeIdxsCoverage(unsigned NumTypeIdxs) const { +#ifndef NDEBUG + if (Rules.empty()) { + DEBUG(dbgs() << ".. type index coverage check SKIPPED: no rules defined\n"); + return true; + } + const int64_t FirstUncovered = TypeIdxsCovered.find_first_unset(); + if (FirstUncovered < 0) { + DEBUG(dbgs() << ".. type index coverage check SKIPPED:" + " user-defined predicate detected\n"); + return true; + } + const bool AllCovered = (FirstUncovered >= NumTypeIdxs); + DEBUG(dbgs() << ".. the first uncovered type index: " << FirstUncovered + << ", " << (AllCovered ? "OK" : "FAIL") << "\n"); + return AllCovered; +#else + return true; +#endif +} + LegalizerInfo::LegalizerInfo() : TablesInitialized(false) { // Set defaults. // FIXME: these two (G_ANYEXT and G_TRUNC?) can be legalized to the @@ -515,6 +537,35 @@ IntermediateType.getScalarSizeInBits())}; } +/// \pre Type indices of every opcode form a dense set starting from 0. +void LegalizerInfo::verify(const MCInstrInfo &MII) const { +#ifndef NDEBUG + std::vector FailedOpcodes; + for (unsigned Opcode = FirstOp; Opcode <= LastOp; ++Opcode) { + const MCInstrDesc &MCID = MII.get(Opcode); + const unsigned NumTypeIdxs = std::accumulate( + MCID.opInfo_begin(), MCID.opInfo_end(), 0U, + [](unsigned Acc, const MCOperandInfo &OpInfo) { + return OpInfo.isGenericType() + ? std::max(OpInfo.getGenericTypeIndex() + 1U, Acc) + : Acc; + }); + DEBUG(dbgs() << MII.getName(Opcode) << " (opcode " << Opcode + << "): " << NumTypeIdxs << " type ind" + << (NumTypeIdxs == 1 ? "ex" : "ices") << "\n"); + const LegalizeRuleSet &RuleSet = getActionDefinitions(Opcode); + if (!RuleSet.verifyTypeIdxsCoverage(NumTypeIdxs)) + FailedOpcodes.push_back(Opcode); + } + if (!FailedOpcodes.empty()) { + errs() << "The following opcodes have ill-defined legalization rules:"; + for (unsigned Opcode : FailedOpcodes) + errs() << " " << MII.getName(Opcode); + errs() << "\n"; + } +#endif +} + #ifndef NDEBUG // FIXME: This should be in the MachineVerifier, but it can't use the // LegalizerInfo as it's currently in the separate GlobalISel library. Index: lib/Target/AArch64/AArch64LegalizerInfo.cpp =================================================================== --- lib/Target/AArch64/AArch64LegalizerInfo.cpp +++ lib/Target/AArch64/AArch64LegalizerInfo.cpp @@ -354,6 +354,7 @@ } computeTables(); + verify(*ST.getInstrInfo()); } bool AArch64LegalizerInfo::legalizeCustom(MachineInstr &MI, Index: test/CodeGen/AArch64/GlobalISel/legalize-inttoptr-xfail-1.mir =================================================================== --- /dev/null +++ test/CodeGen/AArch64/GlobalISel/legalize-inttoptr-xfail-1.mir @@ -0,0 +1,26 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple=aarch64-- -run-pass=legalizer -simplify-mir %s -o - 2>&1 | FileCheck %s + +--- +name: broken +alignment: 2 +tracksRegLiveness: true +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } +body: | + bb.1: + liveins: $x0 + + ; CHECK-LABEL: name: broken + ; CHECK: liveins: $x0 + ; CHECK: [[COPY:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[INTTOPTR:%[0-9]+]]:_(s64) = G_INTTOPTR [[COPY]](p0) + ; CHECK: $x0 = COPY [[INTTOPTR]](s64) + ; CHECK: RET_ReallyLR implicit $x0 + %0:_(p0) = COPY $x0 + %1:_(s64) = G_INTTOPTR %0(p0) + $x0 = COPY %1(s64) + RET_ReallyLR implicit $x0 + +... Index: test/CodeGen/AArch64/GlobalISel/legalize-inttoptr-xfail-2.mir =================================================================== --- /dev/null +++ test/CodeGen/AArch64/GlobalISel/legalize-inttoptr-xfail-2.mir @@ -0,0 +1,26 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple=aarch64-- -run-pass=legalizer -simplify-mir %s -o - 2>&1 | FileCheck %s + +--- +name: broken +alignment: 2 +tracksRegLiveness: true +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } +body: | + bb.1: + liveins: $d0 + + ; CHECK-LABEL: name: broken + ; CHECK: liveins: $d0 + ; CHECK: [[COPY:%[0-9]+]]:_(<4 x s16>) = COPY $d0 + ; CHECK: [[INTTOPTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[COPY]](<4 x s16>) + ; CHECK: $x0 = COPY [[INTTOPTR]](p0) + ; CHECK: RET_ReallyLR implicit $x0 + %0:_(<4 x s16>) = COPY $d0 + %1:_(p0) = G_INTTOPTR %0(<4 x s16>) + $x0 = COPY %1(p0) + RET_ReallyLR implicit $x0 + +... Index: test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir =================================================================== --- /dev/null +++ test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir @@ -0,0 +1,294 @@ +# RUN: llc -mtriple=aarch64-- -run-pass=legalizer %s \ +# RUN: -mcpu=cortex-a75 -o - 2>&1 | FileCheck %s --check-prefixes=CHECK --match-full-lines + +# RUN: llc -mtriple=aarch64-- -run-pass=legalizer %s -debug-only=legalizer-info \ +# RUN: -mcpu=cortex-a75 -o - 2>&1 | FileCheck %s --check-prefixes=CHECK,DEBUG --match-full-lines + +# REQUIRES: asserts + +# The main purpose of this test is to make sure we don't over-relax +# LegalizerInfo validation and loose its ability to catch bugs. +# +# Watch out for every "SKIPPED: user-defined predicate detected" in the +# check-lines below and keep each and every one of them justified. + + +# DEBUG: G_ADD (opcode [[ADD_OPC:[0-9]+]]): 1 type index +# DEBUG-NEXT: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_SUB (opcode [[SUB_OPC:[0-9]+]]): 1 type index +# DEBUG-NEXT: .. opcode [[SUB_OPC]] is aliased to [[ADD_OPC]] +# DEBUG-NEXT: .. opcode [[ADD_OPC]] is aliased to 0 +# DEBUG-NEXT: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_MUL (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_SDIV (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_UDIV (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_SREM (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_UREM (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_AND (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_OR (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_XOR (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_IMPLICIT_DEF (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_PHI (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_FRAME_INDEX (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_GLOBAL_VALUE (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_EXTRACT (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. type index coverage check SKIPPED: user-defined predicate detected +# +# DEBUG-NEXT: G_UNMERGE_VALUES (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. type index coverage check SKIPPED: user-defined predicate detected +# +# DEBUG-NEXT: G_INSERT (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. type index coverage check SKIPPED: user-defined predicate detected +# +# DEBUG-NEXT: G_MERGE_VALUES (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. type index coverage check SKIPPED: user-defined predicate detected +# +# DEBUG-NEXT: G_PTRTOINT (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_INTTOPTR (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 1, FAIL +# +# DEBUG-NEXT: G_BITCAST (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_LOAD (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. type index coverage check SKIPPED: user-defined predicate detected +# +# DEBUG-NEXT: G_SEXTLOAD (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. type index coverage check SKIPPED: user-defined predicate detected +# +# DEBUG-NEXT: G_ZEXTLOAD (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. type index coverage check SKIPPED: user-defined predicate detected +# +# DEBUG-NEXT: G_STORE (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. type index coverage check SKIPPED: user-defined predicate detected +# +# DEBUG-NEXT: G_ATOMIC_CMPXCHG_WITH_SUCCESS (opcode {{[0-9]+}}): 3 type indices +# DEBUG: .. the first uncovered type index: 1, FAIL +# +# DEBUG-NEXT: G_ATOMIC_CMPXCHG (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_ATOMICRMW_XCHG (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_ATOMICRMW_ADD (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_ATOMICRMW_SUB (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_ATOMICRMW_AND (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_ATOMICRMW_NAND (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_ATOMICRMW_OR (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_ATOMICRMW_XOR (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_ATOMICRMW_MAX (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_ATOMICRMW_MIN (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_ATOMICRMW_UMAX (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_ATOMICRMW_UMIN (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_BRCOND (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_BRINDIRECT (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_INTRINSIC (opcode {{[0-9]+}}): 0 type indices +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_INTRINSIC_W_SIDE_EFFECTS (opcode {{[0-9]+}}): 0 type indices +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_ANYEXT (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 1, FAIL +# +# DEBUG-NEXT: G_TRUNC (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_CONSTANT (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_FCONSTANT (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_VASTART (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_VAARG (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_SEXT (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 1, FAIL +# +# DEBUG-NEXT: G_ZEXT (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 1, FAIL +# +# DEBUG-NEXT: G_SHL (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_LSHR (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_ASHR (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_ICMP (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_FCMP (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_SELECT (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_UADDE (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_USUBE (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_SADDO (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_SSUBO (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_UMULO (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_SMULO (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_UMULH (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_SMULH (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_FADD (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_FSUB (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_FMUL (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_FMA (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_FDIV (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_FREM (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_FPOW (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_FEXP (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_FEXP2 (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_FLOG (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_FLOG2 (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_FNEG (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_FPEXT (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_FPTRUNC (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_FPTOSI (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_FPTOUI (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_SITOFP (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_UITOFP (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_FABS (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_GEP (opcode {{[0-9]+}}): 2 type indices +# DEBUG: .. the first uncovered type index: 2, OK +# +# DEBUG-NEXT: G_PTR_MASK (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK +# +# DEBUG-NEXT: G_BR (opcode {{[0-9]+}}): 0 type indices +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_INSERT_VECTOR_ELT (opcode {{[0-9]+}}): 3 type indices +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_EXTRACT_VECTOR_ELT (opcode {{[0-9]+}}): 3 type indices +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_SHUFFLE_VECTOR (opcode {{[0-9]+}}): 3 type indices +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_BSWAP (opcode {{[0-9]+}}): 1 type index +# DEBUG: .. the first uncovered type index: 1, OK + +# CHECK: The following opcodes have ill-defined legalization rules: G_INTTOPTR G_ATOMIC_CMPXCHG_WITH_SUCCESS G_ANYEXT G_SEXT G_ZEXT + +--- +name: dummy +body: | + bb.0: +...