Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(556)

Side by Side Diff: lib/Target/JSBackend/AllocaManager.cpp

Issue 1692803002: Remove Emscripten support (Closed) Base URL: https://chromium.googlesource.com/a/native_client/pnacl-llvm.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/Target/JSBackend/AllocaManager.h ('k') | lib/Target/JSBackend/CMakeLists.txt » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 //===-- AllocaManager.cpp -------------------------------------------------===//
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 // This file defines the AllocaManager class.
11 //
12 // The AllocaManager computes a frame layout, assigning every static alloca an
13 // offset. It does alloca liveness analysis in order to reuse stack memory,
14 // using lifetime intrinsics.
15 //
16 //===----------------------------------------------------------------------===//
17
18 #define DEBUG_TYPE "allocamanager"
19 #include "AllocaManager.h"
20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/IR/DataLayout.h"
22 #include "llvm/IR/IntrinsicInst.h"
23 #include "llvm/IR/Module.h"
24 #include "llvm/IR/CFG.h"
25 #include "llvm/Support/Debug.h"
26 #include "llvm/Support/raw_ostream.h"
27 #include "llvm/Support/Timer.h"
28 #include "llvm/ADT/Statistic.h"
29 using namespace llvm;
30
31 STATISTIC(NumAllocas, "Number of allocas eliminated");
32
33 // Return the size of the given alloca.
34 uint64_t AllocaManager::getSize(const AllocaInst *AI) {
35 assert(AI->isStaticAlloca());
36 return DL->getTypeAllocSize(AI->getAllocatedType()) *
37 cast<ConstantInt>(AI->getArraySize())->getValue().getZExtValue();
38 }
39
40 // Return the alignment of the given alloca.
41 unsigned AllocaManager::getAlignment(const AllocaInst *AI) {
42 assert(AI->isStaticAlloca());
43 unsigned Alignment = std::max(AI->getAlignment(),
44 DL->getABITypeAlignment(AI->getAllocatedType())) ;
45 MaxAlignment = std::max(Alignment, MaxAlignment);
46 return Alignment;
47 }
48
49 AllocaManager::AllocaInfo AllocaManager::getInfo(const AllocaInst *AI) {
50 assert(AI->isStaticAlloca());
51 return AllocaInfo(AI, getSize(AI), getAlignment(AI));
52 }
53
54 // Given a lifetime_start or lifetime_end intrinsic, determine if it's
55 // describing a single pointer suitable for our analysis. If so,
56 // return the pointer, otherwise return NULL.
57 const Value *
58 AllocaManager::getPointerFromIntrinsic(const CallInst *CI) {
59 const IntrinsicInst *II = cast<IntrinsicInst>(CI);
60 assert(II->getIntrinsicID() == Intrinsic::lifetime_start ||
61 II->getIntrinsicID() == Intrinsic::lifetime_end);
62
63 // Lifetime intrinsics have a size as their first argument and a pointer as
64 // their second argument.
65 const Value *Size = II->getArgOperand(0);
66 const Value *Ptr = II->getArgOperand(1);
67
68 // Check to see if we can convert the size to a host integer. If we can't,
69 // it's probably not worth worrying about.
70 const ConstantInt *SizeCon = dyn_cast<ConstantInt>(Size);
71 if (!SizeCon) return NULL;
72 const APInt &SizeAP = SizeCon->getValue();
73 if (SizeAP.getActiveBits() > 64) return NULL;
74 uint64_t MarkedSize = SizeAP.getZExtValue();
75
76 // Test whether the pointer operand is an alloca. This ought to be pretty
77 // simple, but e.g. PRE can decide to PRE bitcasts and no-op geps and
78 // split critical edges and insert phis for them, even though it's all
79 // just no-ops, so we have to dig through phis to see whether all the
80 // inputs are in fact the same pointer after stripping away casts.
81 const Value *Result = NULL;
82 SmallPtrSet<const PHINode *, 8> VisitedPhis;
83 SmallVector<const Value *, 8> Worklist;
84 Worklist.push_back(Ptr);
85 do {
86 const Value *P = Worklist.pop_back_val()->stripPointerCasts();
87
88 if (const PHINode *Phi = dyn_cast<PHINode>(P)) {
89 if (!VisitedPhis.insert(Phi).second)
90 continue;
91 for (unsigned i = 0, e = Phi->getNumOperands(); i < e; ++i)
92 Worklist.push_back(Phi->getOperand(i));
93 continue;
94 }
95 if (const SelectInst *Select = dyn_cast<SelectInst>(P)) {
96 Worklist.push_back(Select->getTrueValue());
97 Worklist.push_back(Select->getFalseValue());
98 continue;
99 }
100
101 if (Result == NULL)
102 Result = P;
103 else if (Result != P)
104 return NULL;
105 } while (!Worklist.empty());
106
107 // If it's a static Alloca, make sure the size is suitable. We test this here
108 // because if this fails, we need to be as conservative as if we don't know
109 // what the pointer is.
110 if (const AllocaInst *AI = dyn_cast<AllocaInst>(Result)) {
111 if (AI->isStaticAlloca() && MarkedSize < getSize(AI))
112 return NULL;
113 } else if (isa<Instruction>(Result)) {
114 // And if it's any other kind of non-object/argument, we have to be
115 // similarly conservative, because we may be dealing with an escaped alloca
116 // that we can't see.
117 return NULL;
118 }
119
120 // Yay, it's all just one Value!
121 return Result;
122 }
123
124 // Test whether the given value is an alloca which we have a hope of
125 const AllocaInst *AllocaManager::isFavorableAlloca(const Value *V) {
126 const AllocaInst *AI = dyn_cast<AllocaInst>(V);
127 if (!AI) return NULL;
128
129 if (!AI->isStaticAlloca()) return NULL;
130
131 return AI;
132 }
133
134 int AllocaManager::AllocaSort(const AllocaInfo *li, const AllocaInfo *ri) {
135 // Sort by alignment to minimize padding.
136 if (li->getAlignment() > ri->getAlignment()) return -1;
137 if (li->getAlignment() < ri->getAlignment()) return 1;
138
139 // Ensure a stable sort. We can do this because the pointers are
140 // pointing into the same array.
141 if (li > ri) return -1;
142 if (li < ri) return 1;
143
144 return 0;
145 }
146
147 // Collect allocas
148 void AllocaManager::collectMarkedAllocas() {
149 NamedRegionTimer Timer("Collect Marked Allocas", "AllocaManager",
150 TimePassesIsEnabled);
151
152 // Weird semantics: If an alloca *ever* appears in a lifetime start or end
153 // within the same function, its lifetime begins only at the explicit lifetime
154 // starts and ends only at the explicit lifetime ends and function exit
155 // points. Otherwise, its lifetime begins in the entry block and it is live
156 // everywhere.
157 //
158 // And so, instead of just walking the entry block to find all the static
159 // allocas, we walk the whole body to find the intrinsics so we can find the
160 // set of static allocas referenced in the intrinsics.
161 for (Function::const_iterator FI = F->begin(), FE = F->end();
162 FI != FE; ++FI) {
163 for (BasicBlock::const_iterator BI = FI->begin(), BE = FI->end();
164 BI != BE; ++BI) {
165 const CallInst *CI = dyn_cast<CallInst>(BI);
166 if (!CI) continue;
167
168 const Value *Callee = CI->getCalledValue();
169 if (Callee == LifetimeStart || Callee == LifetimeEnd) {
170 if (const Value *Ptr = getPointerFromIntrinsic(CI)) {
171 if (const AllocaInst *AI = isFavorableAlloca(Ptr))
172 Allocas.insert(std::make_pair(AI, 0));
173 } else if (isa<Instruction>(CI->getArgOperand(1)->stripPointerCasts())) {
174 // Oh noes, There's a lifetime intrinsics with something that
175 // doesn't appear to resolve to an alloca. This means that it's
176 // possible that it may be declaring a lifetime for some escaping
177 // alloca. Look out!
178 Allocas.clear();
179 assert(AllocasByIndex.empty());
180 return;
181 }
182 }
183 }
184 }
185
186 // All that said, we still want the intrinsics in the order they appear in the
187 // block, so that we can represent later ones with earlier ones and skip
188 // worrying about dominance, so run through the entry block and index those
189 // allocas which we identified above.
190 AllocasByIndex.reserve(Allocas.size());
191 const BasicBlock *EntryBB = &F->getEntryBlock();
192 for (BasicBlock::const_iterator BI = EntryBB->begin(), BE = EntryBB->end();
193 BI != BE; ++BI) {
194 const AllocaInst *AI = dyn_cast<AllocaInst>(BI);
195 if (!AI || !AI->isStaticAlloca()) continue;
196
197 AllocaMap::iterator I = Allocas.find(AI);
198 if (I != Allocas.end()) {
199 I->second = AllocasByIndex.size();
200 AllocasByIndex.push_back(getInfo(AI));
201 }
202 }
203 assert(AllocasByIndex.size() == Allocas.size());
204 }
205
206 // Calculate the starting point from which inter-block liveness will be
207 // computed.
208 void AllocaManager::collectBlocks() {
209 NamedRegionTimer Timer("Collect Blocks", "AllocaManager",
210 TimePassesIsEnabled);
211
212 size_t AllocaCount = AllocasByIndex.size();
213
214 BitVector Seen(AllocaCount);
215
216 for (Function::const_iterator I = F->begin(), E = F->end(); I != E; ++I) {
217 const BasicBlock *BB = I;
218
219 BlockLifetimeInfo &BLI = BlockLiveness[BB];
220 BLI.Start.resize(AllocaCount);
221 BLI.End.resize(AllocaCount);
222
223 // Track which allocas we've seen. This is used because if a lifetime start
224 // is the first lifetime marker for an alloca in a block, the alloca is
225 // live-in.
226 Seen.reset();
227
228 // Walk the instructions and compute the Start and End sets.
229 for (BasicBlock::const_iterator BI = BB->begin(), BE = BB->end();
230 BI != BE; ++BI) {
231 const CallInst *CI = dyn_cast<CallInst>(BI);
232 if (!CI) continue;
233
234 const Value *Callee = CI->getCalledValue();
235 if (Callee == LifetimeStart) {
236 if (const Value *Ptr = getPointerFromIntrinsic(CI)) {
237 if (const AllocaInst *AI = isFavorableAlloca(Ptr)) {
238 AllocaMap::const_iterator MI = Allocas.find(AI);
239 if (MI != Allocas.end()) {
240 size_t AllocaIndex = MI->second;
241 if (!Seen.test(AllocaIndex)) {
242 BLI.Start.set(AllocaIndex);
243 }
244 BLI.End.reset(AllocaIndex);
245 Seen.set(AllocaIndex);
246 }
247 }
248 }
249 } else if (Callee == LifetimeEnd) {
250 if (const Value *Ptr = getPointerFromIntrinsic(CI)) {
251 if (const AllocaInst *AI = isFavorableAlloca(Ptr)) {
252 AllocaMap::const_iterator MI = Allocas.find(AI);
253 if (MI != Allocas.end()) {
254 size_t AllocaIndex = MI->second;
255 BLI.End.set(AllocaIndex);
256 Seen.set(AllocaIndex);
257 }
258 }
259 }
260 }
261 }
262
263 // Lifetimes that start in this block and do not end here are live-out.
264 BLI.LiveOut = BLI.Start;
265 BLI.LiveOut.reset(BLI.End);
266 if (BLI.LiveOut.any()) {
267 for (succ_const_iterator SI = succ_begin(BB), SE = succ_end(BB);
268 SI != SE; ++SI) {
269 InterBlockTopDownWorklist.insert(*SI);
270 }
271 }
272
273 // Lifetimes that end in this block and do not start here are live-in.
274 // TODO: Is this actually true? What are the semantics of a standalone
275 // lifetime end? See also the code in computeInterBlockLiveness.
276 BLI.LiveIn = BLI.End;
277 BLI.LiveIn.reset(BLI.Start);
278 if (BLI.LiveIn.any()) {
279 for (const_pred_iterator PI = pred_begin(BB), PE = pred_end(BB);
280 PI != PE; ++PI) {
281 InterBlockBottomUpWorklist.insert(*PI);
282 }
283 }
284 }
285 }
286
287 // Compute the LiveIn and LiveOut sets for each block in F.
288 void AllocaManager::computeInterBlockLiveness() {
289 NamedRegionTimer Timer("Compute inter-block liveness", "AllocaManager",
290 TimePassesIsEnabled);
291
292 size_t AllocaCount = AllocasByIndex.size();
293
294 BitVector Temp(AllocaCount);
295
296 // Proporgate liveness backwards.
297 while (!InterBlockBottomUpWorklist.empty()) {
298 const BasicBlock *BB = InterBlockBottomUpWorklist.pop_back_val();
299 BlockLifetimeInfo &BLI = BlockLiveness[BB];
300
301 // Compute the new live-out set.
302 for (succ_const_iterator SI = succ_begin(BB), SE = succ_end(BB);
303 SI != SE; ++SI) {
304 Temp |= BlockLiveness[*SI].LiveIn;
305 }
306
307 // If it contains new live blocks, prepare to propagate them.
308 // TODO: As above, what are the semantics of a standalone lifetime end?
309 Temp.reset(BLI.Start);
310 if (Temp.test(BLI.LiveIn)) {
311 BLI.LiveIn |= Temp;
312 for (const_pred_iterator PI = pred_begin(BB), PE = pred_end(BB);
313 PI != PE; ++PI) {
314 InterBlockBottomUpWorklist.insert(*PI);
315 }
316 }
317 Temp.reset();
318 }
319
320 // Proporgate liveness forwards.
321 while (!InterBlockTopDownWorklist.empty()) {
322 const BasicBlock *BB = InterBlockTopDownWorklist.pop_back_val();
323 BlockLifetimeInfo &BLI = BlockLiveness[BB];
324
325 // Compute the new live-in set.
326 for (const_pred_iterator PI = pred_begin(BB), PE = pred_end(BB);
327 PI != PE; ++PI) {
328 Temp |= BlockLiveness[*PI].LiveOut;
329 }
330
331 // Also record the live-in values.
332 BLI.LiveIn |= Temp;
333
334 // If it contains new live blocks, prepare to propagate them.
335 Temp.reset(BLI.End);
336 if (Temp.test(BLI.LiveOut)) {
337 BLI.LiveOut |= Temp;
338 for (succ_const_iterator SI = succ_begin(BB), SE = succ_end(BB);
339 SI != SE; ++SI) {
340 InterBlockTopDownWorklist.insert(*SI);
341 }
342 }
343 Temp.reset();
344 }
345 }
346
347 // Determine overlapping liveranges within blocks.
348 void AllocaManager::computeIntraBlockLiveness() {
349 NamedRegionTimer Timer("Compute intra-block liveness", "AllocaManager",
350 TimePassesIsEnabled);
351
352 size_t AllocaCount = AllocasByIndex.size();
353
354 BitVector Current(AllocaCount);
355
356 AllocaCompatibility.resize(AllocaCount, BitVector(AllocaCount, true));
357
358 for (Function::const_iterator I = F->begin(), E = F->end(); I != E; ++I) {
359 const BasicBlock *BB = I;
360 const BlockLifetimeInfo &BLI = BlockLiveness[BB];
361
362 Current = BLI.LiveIn;
363
364 for (int i = Current.find_first(); i >= 0; i = Current.find_next(i)) {
365 AllocaCompatibility[i].reset(Current);
366 }
367
368 for (BasicBlock::const_iterator BI = BB->begin(), BE = BB->end();
369 BI != BE; ++BI) {
370 const CallInst *CI = dyn_cast<CallInst>(BI);
371 if (!CI) continue;
372
373 const Value *Callee = CI->getCalledValue();
374 if (Callee == LifetimeStart) {
375 if (const Value *Ptr = getPointerFromIntrinsic(CI)) {
376 if (const AllocaInst *AI = isFavorableAlloca(Ptr)) {
377 size_t AIndex = Allocas[AI];
378 // We conflict with everything else that's currently live.
379 AllocaCompatibility[AIndex].reset(Current);
380 // Everything else that's currently live conflicts with us.
381 for (int i = Current.find_first(); i >= 0; i = Current.find_next(i)) {
382 AllocaCompatibility[i].reset(AIndex);
383 }
384 // We're now live.
385 Current.set(AIndex);
386 }
387 }
388 } else if (Callee == LifetimeEnd) {
389 if (const Value *Ptr = getPointerFromIntrinsic(CI)) {
390 if (const AllocaInst *AI = isFavorableAlloca(Ptr)) {
391 size_t AIndex = Allocas[AI];
392 // We're no longer live.
393 Current.reset(AIndex);
394 }
395 }
396 }
397 }
398 }
399 }
400
401 // Decide which allocas will represent which other allocas, and if so what their
402 // size and alignment will need to be.
403 void AllocaManager::computeRepresentatives() {
404 NamedRegionTimer Timer("Compute Representatives", "AllocaManager",
405 TimePassesIsEnabled);
406
407 for (size_t i = 0, e = AllocasByIndex.size(); i != e; ++i) {
408 // If we've already represented this alloca with another, don't visit it.
409 if (AllocasByIndex[i].isForwarded()) continue;
410 if (i > size_t(INT_MAX)) continue;
411
412 // Find compatible allocas. This is a simple greedy algorithm.
413 for (int j = int(i); ; ) {
414 assert(j >= int(i));
415 j = AllocaCompatibility[i].find_next(j);
416 assert(j != int(i));
417 if (j < 0) break;
418 if (!AllocaCompatibility[j][i]) continue;
419
420 DEBUG(dbgs() << "Allocas: "
421 "Representing "
422 << AllocasByIndex[j].getInst()->getName() << " "
423 "with "
424 << AllocasByIndex[i].getInst()->getName() << "\n");
425 ++NumAllocas;
426
427 assert(!AllocasByIndex[j].isForwarded());
428
429 AllocasByIndex[i].mergeSize(AllocasByIndex[j].getSize());
430 AllocasByIndex[i].mergeAlignment(AllocasByIndex[j].getAlignment());
431 AllocasByIndex[j].forward(i);
432
433 AllocaCompatibility[i] &= AllocaCompatibility[j];
434 AllocaCompatibility[j].reset();
435 }
436 }
437 }
438
439 void AllocaManager::computeFrameOffsets() {
440 NamedRegionTimer Timer("Compute Frame Offsets", "AllocaManager",
441 TimePassesIsEnabled);
442
443 // Walk through the entry block and collect all the allocas, including the
444 // ones with no lifetime markers that we haven't looked at yet. We walk in
445 // reverse order so that we can set the representative allocas as those that
446 // dominate the others as we go.
447 const BasicBlock *EntryBB = &F->getEntryBlock();
448 for (BasicBlock::const_iterator BI = EntryBB->begin(), BE = EntryBB->end();
449 BI != BE; ++BI) {
450 const AllocaInst *AI = dyn_cast<AllocaInst>(BI);
451 if (!AI || !AI->isStaticAlloca()) continue;
452
453 AllocaMap::const_iterator I = Allocas.find(AI);
454 if (I != Allocas.end()) {
455 // An alloca with lifetime markers. Emit the record we've crafted for it,
456 // if we've chosen to keep it as a representative.
457 const AllocaInfo &Info = AllocasByIndex[I->second];
458 if (!Info.isForwarded()) {
459 SortedAllocas.push_back(Info);
460 }
461 } else {
462 // An alloca with no lifetime markers.
463 SortedAllocas.push_back(getInfo(AI));
464 }
465 }
466
467 // Sort the allocas to hopefully reduce padding.
468 array_pod_sort(SortedAllocas.begin(), SortedAllocas.end(), AllocaSort);
469
470 // Assign stack offsets.
471 uint64_t CurrentOffset = 0;
472 for (SmallVectorImpl<AllocaInfo>::const_iterator I = SortedAllocas.begin(),
473 E = SortedAllocas.end(); I != E; ++I) {
474 const AllocaInfo &Info = *I;
475 uint64_t NewOffset = RoundUpToAlignment(CurrentOffset, Info.getAlignment());
476
477 // For backwards compatibility, align every power-of-two multiple alloca to
478 // its greatest power-of-two factor, up to 8 bytes. In particular, cube2hash
479 // is known to depend on this.
480 // TODO: Consider disabling this and making people fix their code.
481 if (uint64_t Size = Info.getSize()) {
482 uint64_t P2 = uint64_t(1) << countTrailingZeros(Size);
483 unsigned CompatAlign = unsigned(std::min(P2, uint64_t(8)));
484 NewOffset = RoundUpToAlignment(NewOffset, CompatAlign);
485 }
486
487 const AllocaInst *AI = Info.getInst();
488 StaticAllocas[AI] = StaticAllocation(AI, NewOffset);
489
490 CurrentOffset = NewOffset + Info.getSize();
491 }
492
493 // Add allocas that were represented by other allocas to the StaticAllocas map
494 // so that our clients can look them up.
495 for (unsigned i = 0, e = AllocasByIndex.size(); i != e; ++i) {
496 const AllocaInfo &Info = AllocasByIndex[i];
497 if (!Info.isForwarded()) continue;
498 size_t j = Info.getForwardedID();
499 assert(!AllocasByIndex[j].isForwarded());
500
501 StaticAllocaMap::const_iterator I =
502 StaticAllocas.find(AllocasByIndex[j].getInst());
503 assert(I != StaticAllocas.end());
504
505 std::pair<StaticAllocaMap::const_iterator, bool> Pair =
506 StaticAllocas.insert(std::make_pair(AllocasByIndex[i].getInst(),
507 I->second));
508 assert(Pair.second); (void)Pair;
509 }
510
511 // Record the final frame size. Keep the stack pointer 16-byte aligned.
512 FrameSize = CurrentOffset;
513 FrameSize = RoundUpToAlignment(FrameSize, 16);
514
515 DEBUG(dbgs() << "Allocas: "
516 "Statically allocated frame size is " << FrameSize << "\n");
517 }
518
519 AllocaManager::AllocaManager() : MaxAlignment(0) {
520 }
521
522 void AllocaManager::analyze(const Function &Func, const DataLayout &Layout,
523 bool PerformColoring) {
524 NamedRegionTimer Timer("AllocaManager", TimePassesIsEnabled);
525 assert(Allocas.empty());
526 assert(AllocasByIndex.empty());
527 assert(AllocaCompatibility.empty());
528 assert(BlockLiveness.empty());
529 assert(StaticAllocas.empty());
530 assert(SortedAllocas.empty());
531
532 DL = &Layout;
533 F = &Func;
534
535 // Get the declarations for the lifetime intrinsics so we can quickly test to
536 // see if they are used at all, and for use later if they are.
537 const Module *M = F->getParent();
538 LifetimeStart = M->getFunction(Intrinsic::getName(Intrinsic::lifetime_start));
539 LifetimeEnd = M->getFunction(Intrinsic::getName(Intrinsic::lifetime_end));
540
541 // If we are optimizing and the module contains any lifetime intrinsics, run
542 // the alloca coloring algorithm.
543 if (PerformColoring &&
544 ((LifetimeStart && !LifetimeStart->use_empty()) ||
545 (LifetimeEnd && !LifetimeEnd->use_empty()))) {
546
547 collectMarkedAllocas();
548
549 if (!AllocasByIndex.empty()) {
550 DEBUG(dbgs() << "Allocas: "
551 << AllocasByIndex.size() << " marked allocas found\n");
552
553 collectBlocks();
554 computeInterBlockLiveness();
555 computeIntraBlockLiveness();
556 BlockLiveness.clear();
557
558 computeRepresentatives();
559 AllocaCompatibility.clear();
560 }
561 }
562
563 computeFrameOffsets();
564 SortedAllocas.clear();
565 Allocas.clear();
566 AllocasByIndex.clear();
567 }
568
569 void AllocaManager::clear() {
570 StaticAllocas.clear();
571 }
572
573 bool
574 AllocaManager::getFrameOffset(const AllocaInst *AI, uint64_t *Offset) const {
575 assert(AI->isStaticAlloca());
576 StaticAllocaMap::const_iterator I = StaticAllocas.find(AI);
577 assert(I != StaticAllocas.end());
578 *Offset = I->second.Offset;
579 return AI == I->second.Representative;
580 }
581
582 const AllocaInst *
583 AllocaManager::getRepresentative(const AllocaInst *AI) const {
584 assert(AI->isStaticAlloca());
585 StaticAllocaMap::const_iterator I = StaticAllocas.find(AI);
586 assert(I != StaticAllocas.end());
587 return I->second.Representative;
588 }
OLDNEW
« no previous file with comments | « lib/Target/JSBackend/AllocaManager.h ('k') | lib/Target/JSBackend/CMakeLists.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698