blob: cab21007d3f082ef29d429d37c05d39a1b0a8d5c [file] [log] [blame]
Dan Gohman950a13c2015-09-16 16:51:30 +00001//===-- WebAssemblyCFGStackify.cpp - CFG Stackification -------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief This file implements a CFG stacking pass.
12///
Dan Gohmanf52ee172017-02-27 22:38:58 +000013/// This pass inserts BLOCK and LOOP markers to mark the start of scopes, since
Dan Gohman950a13c2015-09-16 16:51:30 +000014/// scope boundaries serve as the labels for WebAssembly's control transfers.
15///
16/// This is sufficient to convert arbitrary CFGs into a form that works on
17/// WebAssembly, provided that all loops are single-entry.
18///
Dan Gohman950a13c2015-09-16 16:51:30 +000019//===----------------------------------------------------------------------===//
20
Dan Gohman950a13c2015-09-16 16:51:30 +000021#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000022#include "WebAssembly.h"
Dan Gohmaned0f1132016-01-30 05:01:06 +000023#include "WebAssemblyMachineFunctionInfo.h"
Dan Gohman950a13c2015-09-16 16:51:30 +000024#include "WebAssemblySubtarget.h"
Dan Gohman4fc4e422016-10-24 19:49:43 +000025#include "WebAssemblyUtilities.h"
Dan Gohman32807932015-11-23 16:19:56 +000026#include "llvm/CodeGen/MachineDominators.h"
Dan Gohman950a13c2015-09-16 16:51:30 +000027#include "llvm/CodeGen/MachineFunction.h"
28#include "llvm/CodeGen/MachineInstrBuilder.h"
29#include "llvm/CodeGen/MachineLoopInfo.h"
Derek Schuff9c3bf312016-01-13 17:10:28 +000030#include "llvm/CodeGen/MachineRegisterInfo.h"
Dan Gohman950a13c2015-09-16 16:51:30 +000031#include "llvm/CodeGen/Passes.h"
32#include "llvm/Support/Debug.h"
33#include "llvm/Support/raw_ostream.h"
34using namespace llvm;
35
36#define DEBUG_TYPE "wasm-cfg-stackify"
37
38namespace {
39class WebAssemblyCFGStackify final : public MachineFunctionPass {
Mehdi Amini117296c2016-10-01 02:56:57 +000040 StringRef getPassName() const override { return "WebAssembly CFG Stackify"; }
Dan Gohman950a13c2015-09-16 16:51:30 +000041
42 void getAnalysisUsage(AnalysisUsage &AU) const override {
43 AU.setPreservesCFG();
Dan Gohman32807932015-11-23 16:19:56 +000044 AU.addRequired<MachineDominatorTree>();
45 AU.addPreserved<MachineDominatorTree>();
Dan Gohman950a13c2015-09-16 16:51:30 +000046 AU.addRequired<MachineLoopInfo>();
47 AU.addPreserved<MachineLoopInfo>();
48 MachineFunctionPass::getAnalysisUsage(AU);
49 }
50
51 bool runOnMachineFunction(MachineFunction &MF) override;
52
53public:
54 static char ID; // Pass identification, replacement for typeid
55 WebAssemblyCFGStackify() : MachineFunctionPass(ID) {}
56};
57} // end anonymous namespace
58
59char WebAssemblyCFGStackify::ID = 0;
60FunctionPass *llvm::createWebAssemblyCFGStackify() {
61 return new WebAssemblyCFGStackify();
62}
63
Dan Gohmanb3aa1ec2015-12-16 19:06:41 +000064/// Test whether Pred has any terminators explicitly branching to MBB, as
65/// opposed to falling through. Note that it's possible (eg. in unoptimized
66/// code) for a branch instruction to both branch to a block and fallthrough
67/// to it, so we check the actual branch operands to see if there are any
68/// explicit mentions.
Dan Gohman35e4a282016-01-08 01:06:00 +000069static bool ExplicitlyBranchesTo(MachineBasicBlock *Pred,
70 MachineBasicBlock *MBB) {
Dan Gohmanb3aa1ec2015-12-16 19:06:41 +000071 for (MachineInstr &MI : Pred->terminators())
72 for (MachineOperand &MO : MI.explicit_operands())
73 if (MO.isMBB() && MO.getMBB() == MBB)
74 return true;
75 return false;
76}
77
Dan Gohman32807932015-11-23 16:19:56 +000078/// Insert a BLOCK marker for branches to MBB (if needed).
Dan Gohman3a643e82016-10-06 22:10:23 +000079static void PlaceBlockMarker(
80 MachineBasicBlock &MBB, MachineFunction &MF,
81 SmallVectorImpl<MachineBasicBlock *> &ScopeTops,
Dan Gohman2726b882016-10-06 22:29:32 +000082 DenseMap<const MachineInstr *, MachineInstr *> &BlockTops,
83 DenseMap<const MachineInstr *, MachineInstr *> &LoopTops,
Dan Gohman3a643e82016-10-06 22:10:23 +000084 const WebAssemblyInstrInfo &TII,
85 const MachineLoopInfo &MLI,
86 MachineDominatorTree &MDT,
87 WebAssemblyFunctionInfo &MFI) {
Dan Gohman8fe7e862015-12-14 22:51:54 +000088 // First compute the nearest common dominator of all forward non-fallthrough
89 // predecessors so that we minimize the time that the BLOCK is on the stack,
90 // which reduces overall stack height.
Dan Gohman32807932015-11-23 16:19:56 +000091 MachineBasicBlock *Header = nullptr;
92 bool IsBranchedTo = false;
93 int MBBNumber = MBB.getNumber();
94 for (MachineBasicBlock *Pred : MBB.predecessors())
95 if (Pred->getNumber() < MBBNumber) {
96 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
Dan Gohmanb3aa1ec2015-12-16 19:06:41 +000097 if (ExplicitlyBranchesTo(Pred, &MBB))
Dan Gohman32807932015-11-23 16:19:56 +000098 IsBranchedTo = true;
99 }
100 if (!Header)
101 return;
102 if (!IsBranchedTo)
Dan Gohman950a13c2015-09-16 16:51:30 +0000103 return;
104
Dan Gohman8fe7e862015-12-14 22:51:54 +0000105 assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors");
Benjamin Krameref0a45a2016-09-05 12:06:47 +0000106 MachineBasicBlock *LayoutPred = &*std::prev(MachineFunction::iterator(&MBB));
Dan Gohman8fe7e862015-12-14 22:51:54 +0000107
108 // If the nearest common dominator is inside a more deeply nested context,
109 // walk out to the nearest scope which isn't more deeply nested.
110 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) {
111 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {
112 if (ScopeTop->getNumber() > Header->getNumber()) {
113 // Skip over an intervening scope.
Benjamin Krameref0a45a2016-09-05 12:06:47 +0000114 I = std::next(MachineFunction::iterator(ScopeTop));
Dan Gohman8fe7e862015-12-14 22:51:54 +0000115 } else {
116 // We found a scope level at an appropriate depth.
117 Header = ScopeTop;
118 break;
119 }
120 }
121 }
122
Dan Gohman8fe7e862015-12-14 22:51:54 +0000123 // Decide where in Header to put the BLOCK.
Dan Gohman32807932015-11-23 16:19:56 +0000124 MachineBasicBlock::iterator InsertPos;
125 MachineLoop *HeaderLoop = MLI.getLoopFor(Header);
Dan Gohman8fe7e862015-12-14 22:51:54 +0000126 if (HeaderLoop && MBB.getNumber() > LoopBottom(HeaderLoop)->getNumber()) {
127 // Header is the header of a loop that does not lexically contain MBB, so
Dan Gohmana187ab22016-02-12 21:19:25 +0000128 // the BLOCK needs to be above the LOOP, after any END constructs.
Dan Gohman32807932015-11-23 16:19:56 +0000129 InsertPos = Header->begin();
Dan Gohman3a643e82016-10-06 22:10:23 +0000130 while (InsertPos->getOpcode() == WebAssembly::END_BLOCK ||
131 InsertPos->getOpcode() == WebAssembly::END_LOOP)
Dan Gohmana187ab22016-02-12 21:19:25 +0000132 ++InsertPos;
Dan Gohman32807932015-11-23 16:19:56 +0000133 } else {
Dan Gohman8887d1f2015-12-25 00:31:02 +0000134 // Otherwise, insert the BLOCK as late in Header as we can, but before the
135 // beginning of the local expression tree and any nested BLOCKs.
Dan Gohman32807932015-11-23 16:19:56 +0000136 InsertPos = Header->getFirstTerminator();
Benjamin Krameref0a45a2016-09-05 12:06:47 +0000137 while (InsertPos != Header->begin() &&
Dan Gohman4fc4e422016-10-24 19:49:43 +0000138 WebAssembly::isChild(*std::prev(InsertPos), MFI) &&
Benjamin Krameref0a45a2016-09-05 12:06:47 +0000139 std::prev(InsertPos)->getOpcode() != WebAssembly::LOOP &&
140 std::prev(InsertPos)->getOpcode() != WebAssembly::END_BLOCK &&
141 std::prev(InsertPos)->getOpcode() != WebAssembly::END_LOOP)
Dan Gohman32807932015-11-23 16:19:56 +0000142 --InsertPos;
Dan Gohman950a13c2015-09-16 16:51:30 +0000143 }
144
Dan Gohman8fe7e862015-12-14 22:51:54 +0000145 // Add the BLOCK.
Dan Gohman2726b882016-10-06 22:29:32 +0000146 MachineInstr *Begin = BuildMI(*Header, InsertPos, DebugLoc(),
147 TII.get(WebAssembly::BLOCK))
Dan Gohman4fc4e422016-10-24 19:49:43 +0000148 .addImm(int64_t(WebAssembly::ExprType::Void));
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000149
150 // Mark the end of the block.
151 InsertPos = MBB.begin();
152 while (InsertPos != MBB.end() &&
Dan Gohman3a643e82016-10-06 22:10:23 +0000153 InsertPos->getOpcode() == WebAssembly::END_LOOP &&
Dan Gohman2726b882016-10-06 22:29:32 +0000154 LoopTops[&*InsertPos]->getParent()->getNumber() >= Header->getNumber())
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000155 ++InsertPos;
Dan Gohman2726b882016-10-06 22:29:32 +0000156 MachineInstr *End = BuildMI(MBB, InsertPos, DebugLoc(),
157 TII.get(WebAssembly::END_BLOCK));
158 BlockTops[End] = Begin;
Dan Gohman8fe7e862015-12-14 22:51:54 +0000159
160 // Track the farthest-spanning scope that ends at this point.
161 int Number = MBB.getNumber();
162 if (!ScopeTops[Number] ||
163 ScopeTops[Number]->getNumber() > Header->getNumber())
164 ScopeTops[Number] = Header;
165}
166
167/// Insert a LOOP marker for a loop starting at MBB (if it's a loop header).
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000168static void PlaceLoopMarker(
169 MachineBasicBlock &MBB, MachineFunction &MF,
170 SmallVectorImpl<MachineBasicBlock *> &ScopeTops,
Dan Gohman2726b882016-10-06 22:29:32 +0000171 DenseMap<const MachineInstr *, MachineInstr *> &LoopTops,
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000172 const WebAssemblyInstrInfo &TII, const MachineLoopInfo &MLI) {
Dan Gohman8fe7e862015-12-14 22:51:54 +0000173 MachineLoop *Loop = MLI.getLoopFor(&MBB);
174 if (!Loop || Loop->getHeader() != &MBB)
175 return;
176
177 // The operand of a LOOP is the first block after the loop. If the loop is the
178 // bottom of the function, insert a dummy block at the end.
179 MachineBasicBlock *Bottom = LoopBottom(Loop);
Benjamin Krameref0a45a2016-09-05 12:06:47 +0000180 auto Iter = std::next(MachineFunction::iterator(Bottom));
Dan Gohman8fe7e862015-12-14 22:51:54 +0000181 if (Iter == MF.end()) {
182 MachineBasicBlock *Label = MF.CreateMachineBasicBlock();
183 // Give it a fake predecessor so that AsmPrinter prints its label.
184 Label->addSuccessor(Label);
185 MF.push_back(Label);
Benjamin Krameref0a45a2016-09-05 12:06:47 +0000186 Iter = std::next(MachineFunction::iterator(Bottom));
Dan Gohman8fe7e862015-12-14 22:51:54 +0000187 }
188 MachineBasicBlock *AfterLoop = &*Iter;
Dan Gohman8fe7e862015-12-14 22:51:54 +0000189
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000190 // Mark the beginning of the loop (after the end of any existing loop that
191 // ends here).
192 auto InsertPos = MBB.begin();
193 while (InsertPos != MBB.end() &&
194 InsertPos->getOpcode() == WebAssembly::END_LOOP)
195 ++InsertPos;
Dan Gohman2726b882016-10-06 22:29:32 +0000196 MachineInstr *Begin = BuildMI(MBB, InsertPos, DebugLoc(),
197 TII.get(WebAssembly::LOOP))
Dan Gohman4fc4e422016-10-24 19:49:43 +0000198 .addImm(int64_t(WebAssembly::ExprType::Void));
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000199
200 // Mark the end of the loop.
201 MachineInstr *End = BuildMI(*AfterLoop, AfterLoop->begin(), DebugLoc(),
202 TII.get(WebAssembly::END_LOOP));
Dan Gohman2726b882016-10-06 22:29:32 +0000203 LoopTops[End] = Begin;
Dan Gohman8fe7e862015-12-14 22:51:54 +0000204
205 assert((!ScopeTops[AfterLoop->getNumber()] ||
206 ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) &&
Dan Gohman442bfce2016-02-16 16:22:41 +0000207 "With block sorting the outermost loop for a block should be first.");
Dan Gohman8fe7e862015-12-14 22:51:54 +0000208 if (!ScopeTops[AfterLoop->getNumber()])
209 ScopeTops[AfterLoop->getNumber()] = &MBB;
Dan Gohman950a13c2015-09-16 16:51:30 +0000210}
211
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000212static unsigned
213GetDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack,
214 const MachineBasicBlock *MBB) {
215 unsigned Depth = 0;
216 for (auto X : reverse(Stack)) {
217 if (X == MBB)
218 break;
219 ++Depth;
220 }
221 assert(Depth < Stack.size() && "Branch destination should be in scope");
222 return Depth;
223}
224
Dan Gohman2726b882016-10-06 22:29:32 +0000225/// In normal assembly languages, when the end of a function is unreachable,
226/// because the function ends in an infinite loop or a noreturn call or similar,
227/// it isn't necessary to worry about the function return type at the end of
228/// the function, because it's never reached. However, in WebAssembly, blocks
229/// that end at the function end need to have a return type signature that
230/// matches the function signature, even though it's unreachable. This function
231/// checks for such cases and fixes up the signatures.
232static void FixEndsAtEndOfFunction(
233 MachineFunction &MF,
234 const WebAssemblyFunctionInfo &MFI,
235 DenseMap<const MachineInstr *, MachineInstr *> &BlockTops,
236 DenseMap<const MachineInstr *, MachineInstr *> &LoopTops) {
237 assert(MFI.getResults().size() <= 1);
238
239 if (MFI.getResults().empty())
240 return;
241
242 WebAssembly::ExprType retType;
243 switch (MFI.getResults().front().SimpleTy) {
Dan Gohman4fc4e422016-10-24 19:49:43 +0000244 case MVT::i32: retType = WebAssembly::ExprType::I32; break;
245 case MVT::i64: retType = WebAssembly::ExprType::I64; break;
246 case MVT::f32: retType = WebAssembly::ExprType::F32; break;
247 case MVT::f64: retType = WebAssembly::ExprType::F64; break;
248 case MVT::v16i8: retType = WebAssembly::ExprType::I8x16; break;
249 case MVT::v8i16: retType = WebAssembly::ExprType::I16x8; break;
250 case MVT::v4i32: retType = WebAssembly::ExprType::I32x4; break;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000251 case MVT::v4f32: retType = WebAssembly::ExprType::F32x4; break;
Heejin Ahn0de58722018-03-08 04:05:37 +0000252 case MVT::ExceptRef: retType = WebAssembly::ExprType::ExceptRef; break;
Dan Gohman2726b882016-10-06 22:29:32 +0000253 default: llvm_unreachable("unexpected return type");
254 }
255
256 for (MachineBasicBlock &MBB : reverse(MF)) {
257 for (MachineInstr &MI : reverse(MBB)) {
258 if (MI.isPosition() || MI.isDebugValue())
259 continue;
260 if (MI.getOpcode() == WebAssembly::END_BLOCK) {
261 BlockTops[&MI]->getOperand(0).setImm(int32_t(retType));
262 continue;
263 }
264 if (MI.getOpcode() == WebAssembly::END_LOOP) {
265 LoopTops[&MI]->getOperand(0).setImm(int32_t(retType));
266 continue;
267 }
268 // Something other than an `end`. We're done.
269 return;
270 }
271 }
272}
273
Dan Gohmand934cb82017-02-24 23:18:00 +0000274// WebAssembly functions end with an end instruction, as if the function body
275// were a block.
276static void AppendEndToFunction(
277 MachineFunction &MF,
278 const WebAssemblyInstrInfo &TII) {
279 BuildMI(MF.back(), MF.back().end(), DebugLoc(),
280 TII.get(WebAssembly::END_FUNCTION));
281}
282
Dan Gohman950a13c2015-09-16 16:51:30 +0000283/// Insert LOOP and BLOCK markers at appropriate places.
284static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,
Dan Gohman32807932015-11-23 16:19:56 +0000285 const WebAssemblyInstrInfo &TII,
Dan Gohmaned0f1132016-01-30 05:01:06 +0000286 MachineDominatorTree &MDT,
287 WebAssemblyFunctionInfo &MFI) {
Dan Gohman8fe7e862015-12-14 22:51:54 +0000288 // For each block whose label represents the end of a scope, record the block
289 // which holds the beginning of the scope. This will allow us to quickly skip
290 // over scoped regions when walking blocks. We allocate one more than the
291 // number of blocks in the function to accommodate for the possible fake block
292 // we may insert at the end.
293 SmallVector<MachineBasicBlock *, 8> ScopeTops(MF.getNumBlockIDs() + 1);
294
Dan Gohman2726b882016-10-06 22:29:32 +0000295 // For each LOOP_END, the corresponding LOOP.
296 DenseMap<const MachineInstr *, MachineInstr *> LoopTops;
297
298 // For each END_BLOCK, the corresponding BLOCK.
299 DenseMap<const MachineInstr *, MachineInstr *> BlockTops;
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000300
Dan Gohman950a13c2015-09-16 16:51:30 +0000301 for (auto &MBB : MF) {
Dan Gohman32807932015-11-23 16:19:56 +0000302 // Place the LOOP for MBB if MBB is the header of a loop.
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000303 PlaceLoopMarker(MBB, MF, ScopeTops, LoopTops, TII, MLI);
Dan Gohman950a13c2015-09-16 16:51:30 +0000304
Dan Gohman32807932015-11-23 16:19:56 +0000305 // Place the BLOCK for MBB if MBB is branched to from above.
Dan Gohman2726b882016-10-06 22:29:32 +0000306 PlaceBlockMarker(MBB, MF, ScopeTops, BlockTops, LoopTops, TII, MLI, MDT, MFI);
Dan Gohman950a13c2015-09-16 16:51:30 +0000307 }
Dan Gohman950a13c2015-09-16 16:51:30 +0000308
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000309 // Now rewrite references to basic blocks to be depth immediates.
310 SmallVector<const MachineBasicBlock *, 8> Stack;
311 for (auto &MBB : reverse(MF)) {
312 for (auto &MI : reverse(MBB)) {
313 switch (MI.getOpcode()) {
314 case WebAssembly::BLOCK:
Dan Gohman3a643e82016-10-06 22:10:23 +0000315 assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <= MBB.getNumber() &&
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000316 "Block should be balanced");
317 Stack.pop_back();
318 break;
319 case WebAssembly::LOOP:
320 assert(Stack.back() == &MBB && "Loop top should be balanced");
321 Stack.pop_back();
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000322 break;
323 case WebAssembly::END_BLOCK:
324 Stack.push_back(&MBB);
325 break;
326 case WebAssembly::END_LOOP:
Dan Gohman2726b882016-10-06 22:29:32 +0000327 Stack.push_back(LoopTops[&MI]->getParent());
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000328 break;
329 default:
330 if (MI.isTerminator()) {
331 // Rewrite MBB operands to be depth immediates.
332 SmallVector<MachineOperand, 4> Ops(MI.operands());
333 while (MI.getNumOperands() > 0)
334 MI.RemoveOperand(MI.getNumOperands() - 1);
335 for (auto MO : Ops) {
336 if (MO.isMBB())
337 MO = MachineOperand::CreateImm(GetDepth(Stack, MO.getMBB()));
338 MI.addOperand(MF, MO);
339 }
340 }
341 break;
342 }
343 }
344 }
345 assert(Stack.empty() && "Control flow should be balanced");
Dan Gohman2726b882016-10-06 22:29:32 +0000346
347 // Fix up block/loop signatures at the end of the function to conform to
348 // WebAssembly's rules.
349 FixEndsAtEndOfFunction(MF, MFI, BlockTops, LoopTops);
Dan Gohmand934cb82017-02-24 23:18:00 +0000350
351 // Add an end instruction at the end of the function body.
352 if (!MF.getSubtarget<WebAssemblySubtarget>()
353 .getTargetTriple().isOSBinFormatELF())
354 AppendEndToFunction(MF, TII);
Dan Gohman32807932015-11-23 16:19:56 +0000355}
Dan Gohman32807932015-11-23 16:19:56 +0000356
Dan Gohman950a13c2015-09-16 16:51:30 +0000357bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {
358 DEBUG(dbgs() << "********** CFG Stackifying **********\n"
359 "********** Function: "
360 << MF.getName() << '\n');
361
362 const auto &MLI = getAnalysis<MachineLoopInfo>();
Dan Gohman32807932015-11-23 16:19:56 +0000363 auto &MDT = getAnalysis<MachineDominatorTree>();
Dan Gohmane0405332016-10-03 22:43:53 +0000364 // Liveness is not tracked for VALUE_STACK physreg.
Dan Gohman950a13c2015-09-16 16:51:30 +0000365 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
Dan Gohmaned0f1132016-01-30 05:01:06 +0000366 WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
Derek Schuff9c3bf312016-01-13 17:10:28 +0000367 MF.getRegInfo().invalidateLiveness();
Dan Gohman950a13c2015-09-16 16:51:30 +0000368
Dan Gohman950a13c2015-09-16 16:51:30 +0000369 // Place the BLOCK and LOOP markers to indicate the beginnings of scopes.
Dan Gohmaned0f1132016-01-30 05:01:06 +0000370 PlaceMarkers(MF, MLI, TII, MDT, MFI);
Dan Gohman32807932015-11-23 16:19:56 +0000371
Dan Gohman950a13c2015-09-16 16:51:30 +0000372 return true;
373}