LegacyLegalizerInfo.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. //===- lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp - Legalizer ---------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // Implement an interface to specify and query how an illegal operation on a
  10. // given type should be expanded.
  11. //
  12. // Issues to be resolved:
  13. // + Make it fast.
  14. // + Support weird types like i3, <7 x i3>, ...
  15. // + Operations with more than one type (ICMP, CMPXCHG, intrinsics, ...)
  16. //
  17. //===----------------------------------------------------------------------===//
  18. #include "llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h"
  19. #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
  20. #include <map>
  21. using namespace llvm;
  22. using namespace LegacyLegalizeActions;
  23. #define DEBUG_TYPE "legalizer-info"
  24. raw_ostream &llvm::operator<<(raw_ostream &OS, LegacyLegalizeAction Action) {
  25. switch (Action) {
  26. case Legal:
  27. OS << "Legal";
  28. break;
  29. case NarrowScalar:
  30. OS << "NarrowScalar";
  31. break;
  32. case WidenScalar:
  33. OS << "WidenScalar";
  34. break;
  35. case FewerElements:
  36. OS << "FewerElements";
  37. break;
  38. case MoreElements:
  39. OS << "MoreElements";
  40. break;
  41. case Bitcast:
  42. OS << "Bitcast";
  43. break;
  44. case Lower:
  45. OS << "Lower";
  46. break;
  47. case Libcall:
  48. OS << "Libcall";
  49. break;
  50. case Custom:
  51. OS << "Custom";
  52. break;
  53. case Unsupported:
  54. OS << "Unsupported";
  55. break;
  56. case NotFound:
  57. OS << "NotFound";
  58. break;
  59. }
  60. return OS;
  61. }
  62. LegacyLegalizerInfo::LegacyLegalizerInfo() {
  63. // Set defaults.
  64. // FIXME: these two (G_ANYEXT and G_TRUNC?) can be legalized to the
  65. // fundamental load/store Jakob proposed. Once loads & stores are supported.
  66. setScalarAction(TargetOpcode::G_ANYEXT, 1, {{1, Legal}});
  67. setScalarAction(TargetOpcode::G_ZEXT, 1, {{1, Legal}});
  68. setScalarAction(TargetOpcode::G_SEXT, 1, {{1, Legal}});
  69. setScalarAction(TargetOpcode::G_TRUNC, 0, {{1, Legal}});
  70. setScalarAction(TargetOpcode::G_TRUNC, 1, {{1, Legal}});
  71. setScalarAction(TargetOpcode::G_INTRINSIC, 0, {{1, Legal}});
  72. setScalarAction(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS, 0, {{1, Legal}});
  73. setLegalizeScalarToDifferentSizeStrategy(
  74. TargetOpcode::G_IMPLICIT_DEF, 0, narrowToSmallerAndUnsupportedIfTooSmall);
  75. setLegalizeScalarToDifferentSizeStrategy(
  76. TargetOpcode::G_ADD, 0, widenToLargerTypesAndNarrowToLargest);
  77. setLegalizeScalarToDifferentSizeStrategy(
  78. TargetOpcode::G_OR, 0, widenToLargerTypesAndNarrowToLargest);
  79. setLegalizeScalarToDifferentSizeStrategy(
  80. TargetOpcode::G_LOAD, 0, narrowToSmallerAndUnsupportedIfTooSmall);
  81. setLegalizeScalarToDifferentSizeStrategy(
  82. TargetOpcode::G_STORE, 0, narrowToSmallerAndUnsupportedIfTooSmall);
  83. setLegalizeScalarToDifferentSizeStrategy(
  84. TargetOpcode::G_BRCOND, 0, widenToLargerTypesUnsupportedOtherwise);
  85. setLegalizeScalarToDifferentSizeStrategy(
  86. TargetOpcode::G_INSERT, 0, narrowToSmallerAndUnsupportedIfTooSmall);
  87. setLegalizeScalarToDifferentSizeStrategy(
  88. TargetOpcode::G_EXTRACT, 0, narrowToSmallerAndUnsupportedIfTooSmall);
  89. setLegalizeScalarToDifferentSizeStrategy(
  90. TargetOpcode::G_EXTRACT, 1, narrowToSmallerAndUnsupportedIfTooSmall);
  91. setScalarAction(TargetOpcode::G_FNEG, 0, {{1, Lower}});
  92. }
  93. void LegacyLegalizerInfo::computeTables() {
  94. assert(TablesInitialized == false);
  95. for (unsigned OpcodeIdx = 0; OpcodeIdx <= LastOp - FirstOp; ++OpcodeIdx) {
  96. const unsigned Opcode = FirstOp + OpcodeIdx;
  97. for (unsigned TypeIdx = 0; TypeIdx != SpecifiedActions[OpcodeIdx].size();
  98. ++TypeIdx) {
  99. // 0. Collect information specified through the setAction API, i.e.
  100. // for specific bit sizes.
  101. // For scalar types:
  102. SizeAndActionsVec ScalarSpecifiedActions;
  103. // For pointer types:
  104. std::map<uint16_t, SizeAndActionsVec> AddressSpace2SpecifiedActions;
  105. // For vector types:
  106. std::map<uint16_t, SizeAndActionsVec> ElemSize2SpecifiedActions;
  107. for (auto LLT2Action : SpecifiedActions[OpcodeIdx][TypeIdx]) {
  108. const LLT Type = LLT2Action.first;
  109. const LegacyLegalizeAction Action = LLT2Action.second;
  110. auto SizeAction = std::make_pair(Type.getSizeInBits(), Action);
  111. if (Type.isPointer())
  112. AddressSpace2SpecifiedActions[Type.getAddressSpace()].push_back(
  113. SizeAction);
  114. else if (Type.isVector())
  115. ElemSize2SpecifiedActions[Type.getElementType().getSizeInBits()]
  116. .push_back(SizeAction);
  117. else
  118. ScalarSpecifiedActions.push_back(SizeAction);
  119. }
  120. // 1. Handle scalar types
  121. {
  122. // Decide how to handle bit sizes for which no explicit specification
  123. // was given.
  124. SizeChangeStrategy S = &unsupportedForDifferentSizes;
  125. if (TypeIdx < ScalarSizeChangeStrategies[OpcodeIdx].size() &&
  126. ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] != nullptr)
  127. S = ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx];
  128. llvm::sort(ScalarSpecifiedActions);
  129. checkPartialSizeAndActionsVector(ScalarSpecifiedActions);
  130. setScalarAction(Opcode, TypeIdx, S(ScalarSpecifiedActions));
  131. }
  132. // 2. Handle pointer types
  133. for (auto PointerSpecifiedActions : AddressSpace2SpecifiedActions) {
  134. llvm::sort(PointerSpecifiedActions.second);
  135. checkPartialSizeAndActionsVector(PointerSpecifiedActions.second);
  136. // For pointer types, we assume that there isn't a meaningfull way
  137. // to change the number of bits used in the pointer.
  138. setPointerAction(
  139. Opcode, TypeIdx, PointerSpecifiedActions.first,
  140. unsupportedForDifferentSizes(PointerSpecifiedActions.second));
  141. }
  142. // 3. Handle vector types
  143. SizeAndActionsVec ElementSizesSeen;
  144. for (auto VectorSpecifiedActions : ElemSize2SpecifiedActions) {
  145. llvm::sort(VectorSpecifiedActions.second);
  146. const uint16_t ElementSize = VectorSpecifiedActions.first;
  147. ElementSizesSeen.push_back({ElementSize, Legal});
  148. checkPartialSizeAndActionsVector(VectorSpecifiedActions.second);
  149. // For vector types, we assume that the best way to adapt the number
  150. // of elements is to the next larger number of elements type for which
  151. // the vector type is legal, unless there is no such type. In that case,
  152. // legalize towards a vector type with a smaller number of elements.
  153. SizeAndActionsVec NumElementsActions;
  154. for (SizeAndAction BitsizeAndAction : VectorSpecifiedActions.second) {
  155. assert(BitsizeAndAction.first % ElementSize == 0);
  156. const uint16_t NumElements = BitsizeAndAction.first / ElementSize;
  157. NumElementsActions.push_back({NumElements, BitsizeAndAction.second});
  158. }
  159. setVectorNumElementAction(
  160. Opcode, TypeIdx, ElementSize,
  161. moreToWiderTypesAndLessToWidest(NumElementsActions));
  162. }
  163. llvm::sort(ElementSizesSeen);
  164. SizeChangeStrategy VectorElementSizeChangeStrategy =
  165. &unsupportedForDifferentSizes;
  166. if (TypeIdx < VectorElementSizeChangeStrategies[OpcodeIdx].size() &&
  167. VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] != nullptr)
  168. VectorElementSizeChangeStrategy =
  169. VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx];
  170. setScalarInVectorAction(
  171. Opcode, TypeIdx, VectorElementSizeChangeStrategy(ElementSizesSeen));
  172. }
  173. }
  174. TablesInitialized = true;
  175. }
  176. // FIXME: inefficient implementation for now. Without ComputeValueVTs we're
  177. // probably going to need specialized lookup structures for various types before
  178. // we have any hope of doing well with something like <13 x i3>. Even the common
  179. // cases should do better than what we have now.
  180. std::pair<LegacyLegalizeAction, LLT>
  181. LegacyLegalizerInfo::getAspectAction(const InstrAspect &Aspect) const {
  182. assert(TablesInitialized && "backend forgot to call computeTables");
  183. // These *have* to be implemented for now, they're the fundamental basis of
  184. // how everything else is transformed.
  185. if (Aspect.Type.isScalar() || Aspect.Type.isPointer())
  186. return findScalarLegalAction(Aspect);
  187. assert(Aspect.Type.isVector());
  188. return findVectorLegalAction(Aspect);
  189. }
  190. LegacyLegalizerInfo::SizeAndActionsVec
  191. LegacyLegalizerInfo::increaseToLargerTypesAndDecreaseToLargest(
  192. const SizeAndActionsVec &v, LegacyLegalizeAction IncreaseAction,
  193. LegacyLegalizeAction DecreaseAction) {
  194. SizeAndActionsVec result;
  195. unsigned LargestSizeSoFar = 0;
  196. if (v.size() >= 1 && v[0].first != 1)
  197. result.push_back({1, IncreaseAction});
  198. for (size_t i = 0; i < v.size(); ++i) {
  199. result.push_back(v[i]);
  200. LargestSizeSoFar = v[i].first;
  201. if (i + 1 < v.size() && v[i + 1].first != v[i].first + 1) {
  202. result.push_back({LargestSizeSoFar + 1, IncreaseAction});
  203. LargestSizeSoFar = v[i].first + 1;
  204. }
  205. }
  206. result.push_back({LargestSizeSoFar + 1, DecreaseAction});
  207. return result;
  208. }
  209. LegacyLegalizerInfo::SizeAndActionsVec
  210. LegacyLegalizerInfo::decreaseToSmallerTypesAndIncreaseToSmallest(
  211. const SizeAndActionsVec &v, LegacyLegalizeAction DecreaseAction,
  212. LegacyLegalizeAction IncreaseAction) {
  213. SizeAndActionsVec result;
  214. if (v.size() == 0 || v[0].first != 1)
  215. result.push_back({1, IncreaseAction});
  216. for (size_t i = 0; i < v.size(); ++i) {
  217. result.push_back(v[i]);
  218. if (i + 1 == v.size() || v[i + 1].first != v[i].first + 1) {
  219. result.push_back({v[i].first + 1, DecreaseAction});
  220. }
  221. }
  222. return result;
  223. }
  224. LegacyLegalizerInfo::SizeAndAction
  225. LegacyLegalizerInfo::findAction(const SizeAndActionsVec &Vec, const uint32_t Size) {
  226. assert(Size >= 1);
  227. // Find the last element in Vec that has a bitsize equal to or smaller than
  228. // the requested bit size.
  229. // That is the element just before the first element that is bigger than Size.
  230. auto It = partition_point(
  231. Vec, [=](const SizeAndAction &A) { return A.first <= Size; });
  232. assert(It != Vec.begin() && "Does Vec not start with size 1?");
  233. int VecIdx = It - Vec.begin() - 1;
  234. LegacyLegalizeAction Action = Vec[VecIdx].second;
  235. switch (Action) {
  236. case Legal:
  237. case Bitcast:
  238. case Lower:
  239. case Libcall:
  240. case Custom:
  241. return {Size, Action};
  242. case FewerElements:
  243. // FIXME: is this special case still needed and correct?
  244. // Special case for scalarization:
  245. if (Vec == SizeAndActionsVec({{1, FewerElements}}))
  246. return {1, FewerElements};
  247. LLVM_FALLTHROUGH;
  248. case NarrowScalar: {
  249. // The following needs to be a loop, as for now, we do allow needing to
  250. // go over "Unsupported" bit sizes before finding a legalizable bit size.
  251. // e.g. (s8, WidenScalar), (s9, Unsupported), (s32, Legal). if Size==8,
  252. // we need to iterate over s9, and then to s32 to return (s32, Legal).
  253. // If we want to get rid of the below loop, we should have stronger asserts
  254. // when building the SizeAndActionsVecs, probably not allowing
  255. // "Unsupported" unless at the ends of the vector.
  256. for (int i = VecIdx - 1; i >= 0; --i)
  257. if (!needsLegalizingToDifferentSize(Vec[i].second) &&
  258. Vec[i].second != Unsupported)
  259. return {Vec[i].first, Action};
  260. llvm_unreachable("");
  261. }
  262. case WidenScalar:
  263. case MoreElements: {
  264. // See above, the following needs to be a loop, at least for now.
  265. for (std::size_t i = VecIdx + 1; i < Vec.size(); ++i)
  266. if (!needsLegalizingToDifferentSize(Vec[i].second) &&
  267. Vec[i].second != Unsupported)
  268. return {Vec[i].first, Action};
  269. llvm_unreachable("");
  270. }
  271. case Unsupported:
  272. return {Size, Unsupported};
  273. case NotFound:
  274. llvm_unreachable("NotFound");
  275. }
  276. llvm_unreachable("Action has an unknown enum value");
  277. }
  278. std::pair<LegacyLegalizeAction, LLT>
  279. LegacyLegalizerInfo::findScalarLegalAction(const InstrAspect &Aspect) const {
  280. assert(Aspect.Type.isScalar() || Aspect.Type.isPointer());
  281. if (Aspect.Opcode < FirstOp || Aspect.Opcode > LastOp)
  282. return {NotFound, LLT()};
  283. const unsigned OpcodeIdx = getOpcodeIdxForOpcode(Aspect.Opcode);
  284. if (Aspect.Type.isPointer() &&
  285. AddrSpace2PointerActions[OpcodeIdx].find(Aspect.Type.getAddressSpace()) ==
  286. AddrSpace2PointerActions[OpcodeIdx].end()) {
  287. return {NotFound, LLT()};
  288. }
  289. const SmallVector<SizeAndActionsVec, 1> &Actions =
  290. Aspect.Type.isPointer()
  291. ? AddrSpace2PointerActions[OpcodeIdx]
  292. .find(Aspect.Type.getAddressSpace())
  293. ->second
  294. : ScalarActions[OpcodeIdx];
  295. if (Aspect.Idx >= Actions.size())
  296. return {NotFound, LLT()};
  297. const SizeAndActionsVec &Vec = Actions[Aspect.Idx];
  298. // FIXME: speed up this search, e.g. by using a results cache for repeated
  299. // queries?
  300. auto SizeAndAction = findAction(Vec, Aspect.Type.getSizeInBits());
  301. return {SizeAndAction.second,
  302. Aspect.Type.isScalar() ? LLT::scalar(SizeAndAction.first)
  303. : LLT::pointer(Aspect.Type.getAddressSpace(),
  304. SizeAndAction.first)};
  305. }
  306. std::pair<LegacyLegalizeAction, LLT>
  307. LegacyLegalizerInfo::findVectorLegalAction(const InstrAspect &Aspect) const {
  308. assert(Aspect.Type.isVector());
  309. // First legalize the vector element size, then legalize the number of
  310. // lanes in the vector.
  311. if (Aspect.Opcode < FirstOp || Aspect.Opcode > LastOp)
  312. return {NotFound, Aspect.Type};
  313. const unsigned OpcodeIdx = getOpcodeIdxForOpcode(Aspect.Opcode);
  314. const unsigned TypeIdx = Aspect.Idx;
  315. if (TypeIdx >= ScalarInVectorActions[OpcodeIdx].size())
  316. return {NotFound, Aspect.Type};
  317. const SizeAndActionsVec &ElemSizeVec =
  318. ScalarInVectorActions[OpcodeIdx][TypeIdx];
  319. LLT IntermediateType;
  320. auto ElementSizeAndAction =
  321. findAction(ElemSizeVec, Aspect.Type.getScalarSizeInBits());
  322. IntermediateType = LLT::fixed_vector(Aspect.Type.getNumElements(),
  323. ElementSizeAndAction.first);
  324. if (ElementSizeAndAction.second != Legal)
  325. return {ElementSizeAndAction.second, IntermediateType};
  326. auto i = NumElements2Actions[OpcodeIdx].find(
  327. IntermediateType.getScalarSizeInBits());
  328. if (i == NumElements2Actions[OpcodeIdx].end()) {
  329. return {NotFound, IntermediateType};
  330. }
  331. const SizeAndActionsVec &NumElementsVec = (*i).second[TypeIdx];
  332. auto NumElementsAndAction =
  333. findAction(NumElementsVec, IntermediateType.getNumElements());
  334. return {NumElementsAndAction.second,
  335. LLT::fixed_vector(NumElementsAndAction.first,
  336. IntermediateType.getScalarSizeInBits())};
  337. }
  338. unsigned LegacyLegalizerInfo::getOpcodeIdxForOpcode(unsigned Opcode) const {
  339. assert(Opcode >= FirstOp && Opcode <= LastOp && "Unsupported opcode");
  340. return Opcode - FirstOp;
  341. }
  342. LegacyLegalizeActionStep
  343. LegacyLegalizerInfo::getAction(const LegalityQuery &Query) const {
  344. for (unsigned i = 0; i < Query.Types.size(); ++i) {
  345. auto Action = getAspectAction({Query.Opcode, i, Query.Types[i]});
  346. if (Action.first != Legal) {
  347. LLVM_DEBUG(dbgs() << ".. (legacy) Type " << i << " Action="
  348. << Action.first << ", " << Action.second << "\n");
  349. return {Action.first, i, Action.second};
  350. } else
  351. LLVM_DEBUG(dbgs() << ".. (legacy) Type " << i << " Legal\n");
  352. }
  353. LLVM_DEBUG(dbgs() << ".. (legacy) Legal\n");
  354. return {Legal, 0, LLT{}};
  355. }