WebAssemblyCFGSort.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. //===-- WebAssemblyCFGSort.cpp - CFG Sorting ------------------------------===//
  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. /// \file
  10. /// This file implements a CFG sorting pass.
  11. ///
  12. /// This pass reorders the blocks in a function to put them into topological
  13. /// order, ignoring loop backedges, and without any loop or exception being
  14. /// interrupted by a block not dominated by the its header, with special care
  15. /// to keep the order as similar as possible to the original order.
  16. ///
  17. ////===----------------------------------------------------------------------===//
  18. #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
  19. #include "Utils/WebAssemblyUtilities.h"
  20. #include "WebAssembly.h"
  21. #include "WebAssemblyExceptionInfo.h"
  22. #include "WebAssemblySortRegion.h"
  23. #include "WebAssemblySubtarget.h"
  24. #include "llvm/ADT/PriorityQueue.h"
  25. #include "llvm/ADT/SetVector.h"
  26. #include "llvm/CodeGen/MachineDominators.h"
  27. #include "llvm/CodeGen/MachineFunction.h"
  28. #include "llvm/CodeGen/MachineLoopInfo.h"
  29. #include "llvm/CodeGen/MachineRegisterInfo.h"
  30. #include "llvm/CodeGen/Passes.h"
  31. #include "llvm/CodeGen/WasmEHFuncInfo.h"
  32. #include "llvm/Support/Debug.h"
  33. #include "llvm/Support/raw_ostream.h"
  34. using namespace llvm;
  35. using WebAssembly::SortRegion;
  36. using WebAssembly::SortRegionInfo;
  37. #define DEBUG_TYPE "wasm-cfg-sort"
  38. // Option to disable EH pad first sorting. Only for testing unwind destination
  39. // mismatches in CFGStackify.
  40. static cl::opt<bool> WasmDisableEHPadSort(
  41. "wasm-disable-ehpad-sort", cl::ReallyHidden,
  42. cl::desc(
  43. "WebAssembly: Disable EH pad-first sort order. Testing purpose only."),
  44. cl::init(false));
  45. namespace {
  46. class WebAssemblyCFGSort final : public MachineFunctionPass {
  47. StringRef getPassName() const override { return "WebAssembly CFG Sort"; }
  48. void getAnalysisUsage(AnalysisUsage &AU) const override {
  49. AU.setPreservesCFG();
  50. AU.addRequired<MachineDominatorTree>();
  51. AU.addPreserved<MachineDominatorTree>();
  52. AU.addRequired<MachineLoopInfo>();
  53. AU.addPreserved<MachineLoopInfo>();
  54. AU.addRequired<WebAssemblyExceptionInfo>();
  55. AU.addPreserved<WebAssemblyExceptionInfo>();
  56. MachineFunctionPass::getAnalysisUsage(AU);
  57. }
  58. bool runOnMachineFunction(MachineFunction &MF) override;
  59. public:
  60. static char ID; // Pass identification, replacement for typeid
  61. WebAssemblyCFGSort() : MachineFunctionPass(ID) {}
  62. };
  63. } // end anonymous namespace
  64. char WebAssemblyCFGSort::ID = 0;
  65. INITIALIZE_PASS(WebAssemblyCFGSort, DEBUG_TYPE,
  66. "Reorders blocks in topological order", false, false)
  67. FunctionPass *llvm::createWebAssemblyCFGSort() {
  68. return new WebAssemblyCFGSort();
  69. }
  70. static void maybeUpdateTerminator(MachineBasicBlock *MBB) {
  71. #ifndef NDEBUG
  72. bool AnyBarrier = false;
  73. #endif
  74. bool AllAnalyzable = true;
  75. for (const MachineInstr &Term : MBB->terminators()) {
  76. #ifndef NDEBUG
  77. AnyBarrier |= Term.isBarrier();
  78. #endif
  79. AllAnalyzable &= Term.isBranch() && !Term.isIndirectBranch();
  80. }
  81. assert((AnyBarrier || AllAnalyzable) &&
  82. "analyzeBranch needs to analyze any block with a fallthrough");
  83. // Find the layout successor from the original block order.
  84. MachineFunction *MF = MBB->getParent();
  85. MachineBasicBlock *OriginalSuccessor =
  86. unsigned(MBB->getNumber() + 1) < MF->getNumBlockIDs()
  87. ? MF->getBlockNumbered(MBB->getNumber() + 1)
  88. : nullptr;
  89. if (AllAnalyzable)
  90. MBB->updateTerminator(OriginalSuccessor);
  91. }
  92. namespace {
  93. // EH pads are selected first regardless of the block comparison order.
  94. // When only one of the BBs is an EH pad, we give a higher priority to it, to
  95. // prevent common mismatches between possibly throwing calls and ehpads they
  96. // unwind to, as in the example below:
  97. //
  98. // bb0:
  99. // call @foo // If this throws, unwind to bb2
  100. // bb1:
  101. // call @bar // If this throws, unwind to bb3
  102. // bb2 (ehpad):
  103. // handler_bb2
  104. // bb3 (ehpad):
  105. // handler_bb3
  106. // continuing code
  107. //
  108. // Because this pass tries to preserve the original BB order, this order will
  109. // not change. But this will result in this try-catch structure in CFGStackify,
  110. // resulting in a mismatch:
  111. // try
  112. // try
  113. // call @foo
  114. // call @bar // This should unwind to bb3, not bb2!
  115. // catch
  116. // handler_bb2
  117. // end
  118. // catch
  119. // handler_bb3
  120. // end
  121. // continuing code
  122. //
  123. // If we give a higher priority to an EH pad whenever it is ready in this
  124. // example, when both bb1 and bb2 are ready, we would pick up bb2 first.
  125. /// Sort blocks by their number.
  126. struct CompareBlockNumbers {
  127. bool operator()(const MachineBasicBlock *A,
  128. const MachineBasicBlock *B) const {
  129. if (!WasmDisableEHPadSort) {
  130. if (A->isEHPad() && !B->isEHPad())
  131. return false;
  132. if (!A->isEHPad() && B->isEHPad())
  133. return true;
  134. }
  135. return A->getNumber() > B->getNumber();
  136. }
  137. };
  138. /// Sort blocks by their number in the opposite order..
  139. struct CompareBlockNumbersBackwards {
  140. bool operator()(const MachineBasicBlock *A,
  141. const MachineBasicBlock *B) const {
  142. if (!WasmDisableEHPadSort) {
  143. if (A->isEHPad() && !B->isEHPad())
  144. return false;
  145. if (!A->isEHPad() && B->isEHPad())
  146. return true;
  147. }
  148. return A->getNumber() < B->getNumber();
  149. }
  150. };
  151. /// Bookkeeping for a region to help ensure that we don't mix blocks not
  152. /// dominated by the its header among its blocks.
  153. struct Entry {
  154. const SortRegion *TheRegion;
  155. unsigned NumBlocksLeft;
  156. /// List of blocks not dominated by Loop's header that are deferred until
  157. /// after all of Loop's blocks have been seen.
  158. std::vector<MachineBasicBlock *> Deferred;
  159. explicit Entry(const SortRegion *R)
  160. : TheRegion(R), NumBlocksLeft(R->getNumBlocks()) {}
  161. };
  162. } // end anonymous namespace
  163. /// Sort the blocks, taking special care to make sure that regions are not
  164. /// interrupted by blocks not dominated by their header.
  165. /// TODO: There are many opportunities for improving the heuristics here.
  166. /// Explore them.
  167. static void sortBlocks(MachineFunction &MF, const MachineLoopInfo &MLI,
  168. const WebAssemblyExceptionInfo &WEI,
  169. const MachineDominatorTree &MDT) {
  170. // Remember original layout ordering, so we can update terminators after
  171. // reordering to point to the original layout successor.
  172. MF.RenumberBlocks();
  173. // Prepare for a topological sort: Record the number of predecessors each
  174. // block has, ignoring loop backedges.
  175. SmallVector<unsigned, 16> NumPredsLeft(MF.getNumBlockIDs(), 0);
  176. for (MachineBasicBlock &MBB : MF) {
  177. unsigned N = MBB.pred_size();
  178. if (MachineLoop *L = MLI.getLoopFor(&MBB))
  179. if (L->getHeader() == &MBB)
  180. for (const MachineBasicBlock *Pred : MBB.predecessors())
  181. if (L->contains(Pred))
  182. --N;
  183. NumPredsLeft[MBB.getNumber()] = N;
  184. }
  185. // Topological sort the CFG, with additional constraints:
  186. // - Between a region header and the last block in the region, there can be
  187. // no blocks not dominated by its header.
  188. // - It's desirable to preserve the original block order when possible.
  189. // We use two ready lists; Preferred and Ready. Preferred has recently
  190. // processed successors, to help preserve block sequences from the original
  191. // order. Ready has the remaining ready blocks. EH blocks are picked first
  192. // from both queues.
  193. PriorityQueue<MachineBasicBlock *, std::vector<MachineBasicBlock *>,
  194. CompareBlockNumbers>
  195. Preferred;
  196. PriorityQueue<MachineBasicBlock *, std::vector<MachineBasicBlock *>,
  197. CompareBlockNumbersBackwards>
  198. Ready;
  199. const auto *EHInfo = MF.getWasmEHFuncInfo();
  200. SortRegionInfo SRI(MLI, WEI);
  201. SmallVector<Entry, 4> Entries;
  202. for (MachineBasicBlock *MBB = &MF.front();;) {
  203. const SortRegion *R = SRI.getRegionFor(MBB);
  204. if (R) {
  205. // If MBB is a region header, add it to the active region list. We can't
  206. // put any blocks that it doesn't dominate until we see the end of the
  207. // region.
  208. if (R->getHeader() == MBB)
  209. Entries.push_back(Entry(R));
  210. // For each active region the block is in, decrement the count. If MBB is
  211. // the last block in an active region, take it off the list and pick up
  212. // any blocks deferred because the header didn't dominate them.
  213. for (Entry &E : Entries)
  214. if (E.TheRegion->contains(MBB) && --E.NumBlocksLeft == 0)
  215. for (auto *DeferredBlock : E.Deferred)
  216. Ready.push(DeferredBlock);
  217. while (!Entries.empty() && Entries.back().NumBlocksLeft == 0)
  218. Entries.pop_back();
  219. }
  220. // The main topological sort logic.
  221. for (MachineBasicBlock *Succ : MBB->successors()) {
  222. // Ignore backedges.
  223. if (MachineLoop *SuccL = MLI.getLoopFor(Succ))
  224. if (SuccL->getHeader() == Succ && SuccL->contains(MBB))
  225. continue;
  226. // Decrement the predecessor count. If it's now zero, it's ready.
  227. if (--NumPredsLeft[Succ->getNumber()] == 0) {
  228. // When we are in a SortRegion, we allow sorting of not only BBs that
  229. // belong to the current (innermost) region but also BBs that are
  230. // dominated by the current region header. But we should not do this for
  231. // exceptions because there can be cases in which, for example:
  232. // EHPad A's unwind destination (where the exception lands when it is
  233. // not caught by EHPad A) is EHPad B, so EHPad B does not belong to the
  234. // exception dominated by EHPad A. But EHPad B is dominated by EHPad A,
  235. // so EHPad B can be sorted within EHPad A's exception. This is
  236. // incorrect because we may end up delegating/rethrowing to an inner
  237. // scope in CFGStackify. So here we make sure those unwind destinations
  238. // are deferred until their unwind source's exception is sorted.
  239. if (EHInfo && EHInfo->hasUnwindSrcs(Succ)) {
  240. SmallPtrSet<MachineBasicBlock *, 4> UnwindSrcs =
  241. EHInfo->getUnwindSrcs(Succ);
  242. bool IsDeferred = false;
  243. for (Entry &E : Entries) {
  244. if (UnwindSrcs.count(E.TheRegion->getHeader())) {
  245. E.Deferred.push_back(Succ);
  246. IsDeferred = true;
  247. break;
  248. }
  249. }
  250. if (IsDeferred)
  251. continue;
  252. }
  253. Preferred.push(Succ);
  254. }
  255. }
  256. // Determine the block to follow MBB. First try to find a preferred block,
  257. // to preserve the original block order when possible.
  258. MachineBasicBlock *Next = nullptr;
  259. while (!Preferred.empty()) {
  260. Next = Preferred.top();
  261. Preferred.pop();
  262. // If X isn't dominated by the top active region header, defer it until
  263. // that region is done.
  264. if (!Entries.empty() &&
  265. !MDT.dominates(Entries.back().TheRegion->getHeader(), Next)) {
  266. Entries.back().Deferred.push_back(Next);
  267. Next = nullptr;
  268. continue;
  269. }
  270. // If Next was originally ordered before MBB, and it isn't because it was
  271. // loop-rotated above the header, it's not preferred.
  272. if (Next->getNumber() < MBB->getNumber() &&
  273. (WasmDisableEHPadSort || !Next->isEHPad()) &&
  274. (!R || !R->contains(Next) ||
  275. R->getHeader()->getNumber() < Next->getNumber())) {
  276. Ready.push(Next);
  277. Next = nullptr;
  278. continue;
  279. }
  280. break;
  281. }
  282. // If we didn't find a suitable block in the Preferred list, check the
  283. // general Ready list.
  284. if (!Next) {
  285. // If there are no more blocks to process, we're done.
  286. if (Ready.empty()) {
  287. maybeUpdateTerminator(MBB);
  288. break;
  289. }
  290. for (;;) {
  291. Next = Ready.top();
  292. Ready.pop();
  293. // If Next isn't dominated by the top active region header, defer it
  294. // until that region is done.
  295. if (!Entries.empty() &&
  296. !MDT.dominates(Entries.back().TheRegion->getHeader(), Next)) {
  297. Entries.back().Deferred.push_back(Next);
  298. continue;
  299. }
  300. break;
  301. }
  302. }
  303. // Move the next block into place and iterate.
  304. Next->moveAfter(MBB);
  305. maybeUpdateTerminator(MBB);
  306. MBB = Next;
  307. }
  308. assert(Entries.empty() && "Active sort region list not finished");
  309. MF.RenumberBlocks();
  310. #ifndef NDEBUG
  311. SmallSetVector<const SortRegion *, 8> OnStack;
  312. // Insert a sentinel representing the degenerate loop that starts at the
  313. // function entry block and includes the entire function as a "loop" that
  314. // executes once.
  315. OnStack.insert(nullptr);
  316. for (auto &MBB : MF) {
  317. assert(MBB.getNumber() >= 0 && "Renumbered blocks should be non-negative.");
  318. const SortRegion *Region = SRI.getRegionFor(&MBB);
  319. if (Region && &MBB == Region->getHeader()) {
  320. // Region header.
  321. if (Region->isLoop()) {
  322. // Loop header. The loop predecessor should be sorted above, and the
  323. // other predecessors should be backedges below.
  324. for (auto *Pred : MBB.predecessors())
  325. assert(
  326. (Pred->getNumber() < MBB.getNumber() || Region->contains(Pred)) &&
  327. "Loop header predecessors must be loop predecessors or "
  328. "backedges");
  329. } else {
  330. // Exception header. All predecessors should be sorted above.
  331. for (auto *Pred : MBB.predecessors())
  332. assert(Pred->getNumber() < MBB.getNumber() &&
  333. "Non-loop-header predecessors should be topologically sorted");
  334. }
  335. assert(OnStack.insert(Region) &&
  336. "Regions should be declared at most once.");
  337. } else {
  338. // Not a region header. All predecessors should be sorted above.
  339. for (auto *Pred : MBB.predecessors())
  340. assert(Pred->getNumber() < MBB.getNumber() &&
  341. "Non-loop-header predecessors should be topologically sorted");
  342. assert(OnStack.count(SRI.getRegionFor(&MBB)) &&
  343. "Blocks must be nested in their regions");
  344. }
  345. while (OnStack.size() > 1 && &MBB == SRI.getBottom(OnStack.back()))
  346. OnStack.pop_back();
  347. }
  348. assert(OnStack.pop_back_val() == nullptr &&
  349. "The function entry block shouldn't actually be a region header");
  350. assert(OnStack.empty() &&
  351. "Control flow stack pushes and pops should be balanced.");
  352. #endif
  353. }
  354. bool WebAssemblyCFGSort::runOnMachineFunction(MachineFunction &MF) {
  355. LLVM_DEBUG(dbgs() << "********** CFG Sorting **********\n"
  356. "********** Function: "
  357. << MF.getName() << '\n');
  358. const auto &MLI = getAnalysis<MachineLoopInfo>();
  359. const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>();
  360. auto &MDT = getAnalysis<MachineDominatorTree>();
  361. // Liveness is not tracked for VALUE_STACK physreg.
  362. MF.getRegInfo().invalidateLiveness();
  363. // Sort the blocks, with contiguous sort regions.
  364. sortBlocks(MF, MLI, WEI, MDT);
  365. return true;
  366. }