36 using namespace LegalizeActions;
38 #define DEBUG_TYPE "legalizer-info"
41 "disable-gisel-legality-check",
42 cl::desc(
"Don't verify that MIR is fully legal between GlobalISel passes"),
57 OS <<
"FewerElements";
81 OS <<
"UseLegacyRules";
88 OS << Opcode <<
", Tys={";
89 for (
const auto &
Type : Types) {
94 OS << Opcode <<
", MMOs={";
95 for (
const auto &MMODescr : MMODescrs) {
96 OS << MMODescr.SizeInBits <<
", ";
106 const std::pair<unsigned, LLT> &
Mutation) {
123 std::pair<unsigned, LLT>
Mutation) {
129 const unsigned TypeIdx =
Mutation.first;
194 LLVM_DEBUG(
dbgs() <<
".. fallback to legacy rules (no rules defined)\n");
198 if (Rule.match(Query)) {
200 std::pair<unsigned, LLT>
Mutation = Rule.determineMutation(Query);
204 "legality mutation invalid for match");
218 dbgs() <<
".. type index coverage check SKIPPED: no rules defined\n");
221 const int64_t FirstUncovered = TypeIdxsCovered.find_first_unset();
222 if (FirstUncovered < 0) {
224 " user-defined predicate detected\n");
227 const bool AllCovered = (FirstUncovered >= NumTypeIdxs);
229 LLVM_DEBUG(
dbgs() <<
".. the first uncovered type index: " << FirstUncovered
230 <<
", " << (AllCovered ?
"OK" :
"FAIL") <<
"\n");
241 dbgs() <<
".. imm index coverage check SKIPPED: no rules defined\n");
244 const int64_t FirstUncovered = ImmIdxsCovered.find_first_unset();
245 if (FirstUncovered < 0) {
247 " user-defined predicate detected\n");
250 const bool AllCovered = (FirstUncovered >= NumImmIdxs);
251 LLVM_DEBUG(
dbgs() <<
".. the first uncovered imm index: " << FirstUncovered
252 <<
", " << (AllCovered ?
"OK" :
"FAIL") <<
"\n");
263 setScalarAction(TargetOpcode::G_ANYEXT, 1, {{1,
Legal}});
264 setScalarAction(TargetOpcode::G_ZEXT, 1, {{1,
Legal}});
265 setScalarAction(TargetOpcode::G_SEXT, 1, {{1,
Legal}});
266 setScalarAction(TargetOpcode::G_TRUNC, 0, {{1,
Legal}});
267 setScalarAction(TargetOpcode::G_TRUNC, 1, {{1,
Legal}});
269 setScalarAction(TargetOpcode::G_INTRINSIC, 0, {{1,
Legal}});
270 setScalarAction(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS, 0, {{1,
Legal}});
291 setScalarAction(TargetOpcode::G_FNEG, 0, {{1,
Lower}});
295 assert(TablesInitialized ==
false);
297 for (
unsigned OpcodeIdx = 0; OpcodeIdx <= LastOp - FirstOp; ++OpcodeIdx) {
298 const unsigned Opcode = FirstOp + OpcodeIdx;
299 for (
unsigned TypeIdx = 0; TypeIdx != SpecifiedActions[OpcodeIdx].size();
306 std::map<uint16_t, SizeAndActionsVec> AddressSpace2SpecifiedActions;
308 std::map<uint16_t, SizeAndActionsVec> ElemSize2SpecifiedActions;
309 for (
auto LLT2Action : SpecifiedActions[OpcodeIdx][TypeIdx]) {
310 const LLT Type = LLT2Action.first;
313 auto SizeAction = std::make_pair(
Type.getSizeInBits(), Action);
314 if (
Type.isPointer())
315 AddressSpace2SpecifiedActions[
Type.getAddressSpace()].push_back(
317 else if (
Type.isVector())
318 ElemSize2SpecifiedActions[
Type.getElementType().getSizeInBits()]
319 .push_back(SizeAction);
321 ScalarSpecifiedActions.push_back(SizeAction);
329 if (TypeIdx < ScalarSizeChangeStrategies[OpcodeIdx].
size() &&
330 ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] !=
nullptr)
331 S = ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx];
333 checkPartialSizeAndActionsVector(ScalarSpecifiedActions);
334 setScalarAction(Opcode, TypeIdx,
S(ScalarSpecifiedActions));
338 for (
auto PointerSpecifiedActions : AddressSpace2SpecifiedActions) {
340 checkPartialSizeAndActionsVector(PointerSpecifiedActions.second);
344 Opcode, TypeIdx, PointerSpecifiedActions.first,
350 for (
auto VectorSpecifiedActions : ElemSize2SpecifiedActions) {
352 const uint16_t ElementSize = VectorSpecifiedActions.first;
353 ElementSizesSeen.push_back({ElementSize,
Legal});
354 checkPartialSizeAndActionsVector(VectorSpecifiedActions.second);
360 for (
SizeAndAction BitsizeAndAction : VectorSpecifiedActions.second) {
361 assert(BitsizeAndAction.first % ElementSize == 0);
362 const uint16_t NumElements = BitsizeAndAction.first / ElementSize;
363 NumElementsActions.push_back({NumElements, BitsizeAndAction.second});
365 setVectorNumElementAction(
366 Opcode, TypeIdx, ElementSize,
372 if (TypeIdx < VectorElementSizeChangeStrategies[OpcodeIdx].
size() &&
373 VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] !=
nullptr)
374 VectorElementSizeChangeStrategy =
375 VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx];
376 setScalarInVectorAction(
377 Opcode, TypeIdx, VectorElementSizeChangeStrategy(ElementSizesSeen));
381 TablesInitialized =
true;
388 std::pair<LegalizeAction, LLT>
389 LegalizerInfo::getAspectAction(
const InstrAspect &Aspect)
const {
390 assert(TablesInitialized &&
"backend forgot to call computeTables");
394 return findScalarLegalAction(Aspect);
396 return findVectorLegalAction(Aspect);
403 assert(TypeIdx <
MI.getNumOperands() &&
"Unexpected TypeIdx");
407 if (
MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES && TypeIdx == 1)
408 return MRI.
getType(
MI.getOperand(
MI.getNumOperands() - 1).getReg());
413 assert(Opcode >= FirstOp && Opcode <= LastOp &&
"Unsupported opcode");
414 return Opcode - FirstOp;
419 if (
unsigned Alias = RulesForOpcode[OpcodeIdx].getAlias()) {
420 LLVM_DEBUG(
dbgs() <<
".. opcode " << Opcode <<
" is aliased to " << Alias
423 assert(RulesForOpcode[OpcodeIdx].getAlias() == 0 &&
"Cannot chain aliases");
432 return RulesForOpcode[OpcodeIdx];
437 auto &Result = RulesForOpcode[OpcodeIdx];
438 assert(!Result.isAliasedByAnother() &&
"Modifying this opcode will modify aliases");
443 std::initializer_list<unsigned> Opcodes) {
444 unsigned Representative = *Opcodes.begin();
447 "Initializer list must have at least two opcodes");
453 Return.setIsAliasedByAnother();
458 unsigned OpcodeFrom) {
459 assert(OpcodeTo != OpcodeFrom &&
"Cannot alias to self");
460 assert(OpcodeTo >= FirstOp && OpcodeTo <= LastOp &&
"Unsupported opcode");
462 RulesForOpcode[OpcodeFromIdx].
aliasTo(OpcodeTo);
472 for (
unsigned i = 0;
i < Query.
Types.size(); ++
i) {
473 auto Action = getAspectAction({Query.
Opcode,
i, Query.
Types[
i]});
474 if (Action.first !=
Legal) {
476 << Action.first <<
", " << Action.second <<
"\n");
477 return {Action.first,
i, Action.second};
492 for (
unsigned i = 0;
i <
MI.getDesc().getNumOperands(); ++
i) {
493 if (!OpInfo[
i].isGenericType())
499 if (SeenTypes[TypeIdx])
502 SeenTypes.
set(TypeIdx);
509 for (
const auto &MMO :
MI.memoperands())
510 MemDescrs.push_back({8 * MMO->getSize() ,
511 8 * MMO->getAlign().value(), MMO->getOrdering()});
513 return getAction({
MI.getOpcode(), Types, MemDescrs});
534 unsigned LargestSizeSoFar = 0;
535 if (v.size() >= 1 && v[0].first != 1)
536 result.push_back({1, IncreaseAction});
537 for (
size_t i = 0;
i < v.size(); ++
i) {
539 LargestSizeSoFar = v[
i].first;
540 if (
i + 1 < v.size() && v[
i + 1].first != v[
i].first + 1) {
541 result.push_back({LargestSizeSoFar + 1, IncreaseAction});
542 LargestSizeSoFar = v[
i].first + 1;
545 result.push_back({LargestSizeSoFar + 1, DecreaseAction});
554 if (v.size() == 0 || v[0].first != 1)
555 result.push_back({1, IncreaseAction});
556 for (
size_t i = 0;
i < v.size(); ++
i) {
558 if (
i + 1 == v.size() || v[
i + 1].first != v[
i].first + 1) {
559 result.push_back({v[
i].first + 1, DecreaseAction});
566 LegalizerInfo::findAction(
const SizeAndActionsVec &Vec,
const uint32_t Size) {
573 assert(It != Vec.begin() &&
"Does Vec not start with size 1?");
574 int VecIdx = It - Vec.begin() - 1;
583 return {
Size, Action};
598 for (
int i = VecIdx - 1;
i >= 0; --
i)
600 Vec[
i].second != Unsupported)
601 return {Vec[
i].first, Action};
607 for (std::size_t
i = VecIdx + 1;
i < Vec.size(); ++
i)
609 Vec[
i].second != Unsupported)
610 return {Vec[
i].first, Action};
622 std::pair<LegalizeAction, LLT>
623 LegalizerInfo::findScalarLegalAction(
const InstrAspect &Aspect)
const {
630 AddrSpace2PointerActions[OpcodeIdx].end()) {
635 ? AddrSpace2PointerActions[OpcodeIdx]
638 : ScalarActions[OpcodeIdx];
639 if (Aspect.
Idx >= Actions.size())
647 :
LLT::pointer(Aspect.
Type.getAddressSpace(),
651 std::pair<LegalizeAction, LLT>
652 LegalizerInfo::findVectorLegalAction(
const InstrAspect &Aspect)
const {
659 const unsigned TypeIdx = Aspect.
Idx;
660 if (TypeIdx >= ScalarInVectorActions[OpcodeIdx].
size())
663 ScalarInVectorActions[OpcodeIdx][TypeIdx];
665 LLT IntermediateType;
666 auto ElementSizeAndAction =
670 if (ElementSizeAndAction.second !=
Legal)
671 return {ElementSizeAndAction.second, IntermediateType};
673 auto i = NumElements2Actions[OpcodeIdx].find(
675 if (
i == NumElements2Actions[OpcodeIdx].
end()) {
676 return {
NotFound, IntermediateType};
679 auto NumElementsAndAction =
681 return {NumElementsAndAction.second,
687 return SmallTy.
isByteSized() ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
693 std::vector<unsigned> FailedOpcodes;
694 for (
unsigned Opcode = FirstOp; Opcode <= LastOp; ++Opcode) {
696 const unsigned NumTypeIdxs = std::accumulate(
699 return OpInfo.isGenericType()
700 ? std::max(OpInfo.getGenericTypeIndex() + 1U, Acc)
703 const unsigned NumImmIdxs = std::accumulate(
706 return OpInfo.isGenericImm()
707 ? std::max(OpInfo.getGenericImmIndex() + 1U, Acc)
711 <<
"): " << NumTypeIdxs <<
" type ind"
712 << (NumTypeIdxs == 1 ?
"ex" :
"ices") <<
", "
713 << NumImmIdxs <<
" imm ind"
714 << (NumImmIdxs == 1 ?
"ex" :
"ices") <<
"\n");
717 FailedOpcodes.push_back(Opcode);
719 FailedOpcodes.push_back(Opcode);
721 if (!FailedOpcodes.empty()) {
722 errs() <<
"The following opcodes have ill-defined legalization rules:";
723 for (
unsigned Opcode : FailedOpcodes)
728 ", try -debug-only=legalizer-info for details");
745 !MLI->isLegalOrCustom(
MI,
MRI))