Chromium Code Reviews

Side by Side Diff: lib/Transforms/NaCl/NormalizeStructRegSignatures.cpp

Issue 992493002: Lower signatures exposing struct registers to byval struct pointers (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-llvm.git@master
Patch Set: First draft Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
OLDNEW
(Empty)
1 //===- NormalizeStructRegSignatures.cpp - Change struct regs to struct ----===//
2 // pointers
3 //
4 // The LLVM Compiler Infrastructure
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License. See LICENSE.TXT for details.
8 //
9 //===----------------------------------------------------------------------===//
10 // We do not support struct registers in PNaCl. We remove them in 2 stages.
11 // In the first stage (this pass), we replace function signatures exposing them
12 // to byval pointer-based signatures:
13 //
14 // @foo(%some_struct %val) -> @foo(%some_struct* byval %val)
15 // or
16 // %someStruct @bar(<other_args>) -> void @bar(%someStruct* sret, <other_args>)
17 //
18 // We also adjust such a function's body and call sites by creating locals to
19 // convert to/from struct reg and struct* byval
20 //
21 // This affects more than function signatures. For example:
22 //
23 // %other_struct = type { i32, i32 }
24 // %struct = type { void (%other_struct)* }
25 // void %func(%struct* byval %s)
26 //
27 // must become:
28 // %other_struct = type {i32, i32}
29 // %struct.1 = type {void (%other_struct*)*}
30 // void %func(%struct.1* byval %s)
31 //
32 // The second removal stage happens in the ExpandStructRegs.cpp phase.
33 //===----------------------------------------------------------------------===//
34
35 #include <stddef.h>
JF 2015/03/08 22:04:38 <cstddef> is more common.
Mircea Trofin 2015/03/09 21:21:29 Acknowledged.
36 #include <cassert>
37
38 #include "llvm/ADT/ArrayRef.h"
39 #include "llvm/ADT/ilist.h"
40 #include "llvm/ADT/DenseSet.h"
41 #include "llvm/ADT/SetVector.h"
42 #include "llvm/ADT/SmallVector.h"
43 #include "llvm/ADT/Twine.h"
44 #include "llvm/IR/Argument.h"
45 #include "llvm/IR/Attributes.h"
46 #include "llvm/IR/BasicBlock.h"
47 #include "llvm/IR/DerivedTypes.h"
48 #include "llvm/IR/Function.h"
49 #include "llvm/IR/GlobalValue.h"
50 #include "llvm/IR/Instructions.h"
51 #include "llvm/IR/Module.h"
52 #include "llvm/IR/Type.h"
53 #include "llvm/IR/Use.h"
54 #include "llvm/IR/User.h"
55 #include "llvm/IR/Value.h"
56 #include "llvm/Pass.h"
57 #include "llvm/PassInfo.h"
58 #include "llvm/PassRegistry.h"
59 #include "llvm/PassSupport.h"
60 #include "llvm/Transforms/NaCl.h"
JF 2015/03/08 22:04:38 You should sort these.
Mircea Trofin 2015/03/09 21:21:29 Done.
61
62 using namespace llvm;
63
64 class MappingResult {
JF 2015/03/08 22:04:38 This should be in an anonymous namespace.
Mircea Trofin 2015/03/09 21:21:29 Done.
65 public:
66
67 MappingResult(Type *ATy, bool Chg) {
68 Ty = ATy;
69 Changed = Chg;
70 }
71
72 bool isChanged() {
73 return Changed;
74 }
75
76 Type *operator->() {
77 return Ty;
78 }
79
80 operator Type*() {
81 return Ty;
82 }
83 private:
84 Type *Ty;
85 bool Changed;
86 };
87
88 // utility class. For any given type, get the associated type that is struct
89 // reg argument - free.
90 class TypeMapper {
91 public:
92 Type *getCompliantType(Type *Ty);
93 private:
94 DenseMap<Type*, Type*> MappedTypes;
95 MappingResult getCompliantArgumentType(Type *Ty);
96 MappingResult getCompliantAggregateTypeInternal(Type *Ty);
97 };
98
99 namespace {
100 // This is a ModulePass because the pass recreates functions in
101 // order to change their signatures.
102 class NormalizeStructRegSignatures : public ModulePass {
103 public:
104 static char ID;
105
106 NormalizeStructRegSignatures() :
107 ModulePass(ID) {
108 initializeNormalizeStructRegSignaturesPass(
109 *PassRegistry::getPassRegistry());
110 }
111 virtual bool runOnModule(Module &M);
112 private:
113 TypeMapper Mapper;
114 DenseSet<Function*> FunctionsToDelete;
115 DenseSet<CallInst*> CallsToPatch;
116 DenseSet<InvokeInst*> InvokesToPatch;
117 DenseMap<Function*, Function*> FunctionMap;
118 bool ensurePNaClComplyingFunction(Function *OldFunc, Module &M);
JF 2015/03/08 22:04:38 I'd avoid putting "PNaCl" in the name: when we ups
Mircea Trofin 2015/03/09 21:21:29 Done.
119 void FixFunctionBody(Function *OldFunc, Function *NewFunc);
120 void ScheduleCallsForCleanup(Function *NewFunc);
121 template <class TCall> void FixCallSite(TCall *Call);
122 };
123 }
124
125 const unsigned int TypicalArity = 8;
JF 2015/03/08 22:04:38 static
Mircea Trofin 2015/03/09 21:21:29 Done.
126
127 char NormalizeStructRegSignatures::ID = 0;
128
129 INITIALIZE_PASS(NormalizeStructRegSignatures, "normalize-struct-reg-signatures",
130 "Normalize function signatures by removing struct register parameters",
131 false,
132 false)
133
134 // The type is "compliant" if it does not recursively reference a
135 // function type with at least an operand (arg or return) typed as struct
136 // register
137 Type *TypeMapper::getCompliantType(Type *Ty) {
138 if (MappedTypes.count(Ty))
139 return MappedTypes[Ty];
140 return MappedTypes[Ty] = getCompliantAggregateTypeInternal(Ty);
141 }
142
143 // transforms any type that could transitively reference a function pointer
144 // into a compliant type.
145 MappingResult TypeMapper::
146 getCompliantAggregateTypeInternal(Type *Ty) {
147 LLVMContext &Ctx = Ty->getContext();
148 if (Ty->isFunctionTy()) {
149 FunctionType *OldFnTy = dyn_cast<FunctionType>(Ty);
JF 2015/03/08 22:04:38 The LLVM-idiomatic way is: if (FunctionType *Old
Mircea Trofin 2015/03/09 21:21:29 Done.
150 Type *OldRetType = OldFnTy->getReturnType();
151 Type *NewRetType = OldRetType;
152 Type *Void = Type::getVoidTy(Ctx);
153 SmallVector<Type*, TypicalArity> NewArgs;
154 bool HasChanges = false;
155 // struct register returns become the first parameter of the new FT.
156 // the new FT has void for the return type
157 if (OldRetType->isAggregateType()) {
158 NewRetType = Void;
159 HasChanges = true;
160 NewArgs.push_back(getCompliantArgumentType(OldRetType));
161 }
162 for (auto OldParam = OldFnTy->param_begin(), E = OldFnTy->param_end();
163 OldParam != E; ++OldParam) {
164 auto NewType = getCompliantArgumentType(*OldParam);
165 HasChanges |= NewType.isChanged();
166 NewArgs.push_back(NewType);
167 }
168 Type *NewFuncType = FunctionType::get(NewRetType, NewArgs, false);
169 return MappingResult(NewFuncType, HasChanges);
170 }
171
172 if (Ty->isPointerTy()) {
173 auto NewTy = getCompliantAggregateTypeInternal(
174 Ty->getPointerElementType());
175
176 return MappingResult(
177 NewTy->getPointerTo(),
178 NewTy.isChanged());
179 }
180
181 if (Ty->isArrayTy()) {
182 auto NewTy = getCompliantAggregateTypeInternal(
183 Ty->getArrayElementType());
184 return MappingResult(
185 ArrayType::get(
186 NewTy,
187 Ty->getArrayNumElements()),
188 NewTy.isChanged());
189 }
190
191 if (Ty->isVectorTy()) {
192 auto NewTy = getCompliantAggregateTypeInternal(
193 Ty->getVectorElementType());
194 return MappingResult(
195 VectorType::get(
196 NewTy,
197 Ty->getVectorNumElements()),
198 NewTy.isChanged());
199 }
200
201 if (Ty->isAggregateType()) {
202 StructType *StructTy = dyn_cast<StructType>(Ty);
203 if (!StructTy->isLiteral()) {
204 // LLVM doesn't intern identified structs (the ones with a name). This,
205 // together with the fact that such structs can be recursive,
206 // complicates things a bit. We want to make sure that we only change
207 // "problem" structs (those that somehow reference noncompliant funcs).
208 // We don't want to change compliant structs, otherwise converting
209 // instruction types will become trickier.
210 Type* &Loc = MappedTypes[StructTy];
JF 2015/03/08 22:04:38 Pointer ref is pretty unusual. Could you instead g
Mircea Trofin 2015/03/09 21:21:29 Yes, but then we spend twice on the hash map locat
211 if (!Loc) {
212 // We don't have a mapping, and we don't know if the struct is recursive
213 // so we create an empty one and hypothesize that it is the
214 // mapping.
215 Loc = StructType::create(Ctx, StructTy->getStructName());
216 } else {
217 // we either have a finished mapping or this is the empty placeholder
218 // created above, and we are in the process of finalizing it.
219 // 1) if this is a mapping, it must have the same element count
220 // as the original struct, so we mark a change if the types are
221 // different objects
222 // 2) if this is a placeholder, the element count will differ.
223 // Since we don't know yet if this is a change or not - because we
224 // are constructing the mapping - we don't mark as change. We decide
225 // if it is a change below, based on the other struct elements.
226 bool hasChanged =
227 StructTy != Loc &&
228 StructTy->getStructNumElements() == Loc->getStructNumElements();
229 return MappingResult(Loc, hasChanged);
230 }
231 }
232
233 SmallVector<Type*, 8> ElemTypes;
JF 2015/03/08 22:04:38 TypicalArity?
Mircea Trofin 2015/03/09 21:21:29 Only I meant TypicalArity to be for functions :) B
234 bool HasChanges = false;
235 for (unsigned I = 0; I < Ty->getStructNumElements(); I++) {
JF 2015/03/08 22:04:38 I'd cache getStructNumElements. It's not expensive
Mircea Trofin 2015/03/09 21:21:29 Done.
236 auto NewElem =
237 getCompliantAggregateTypeInternal(
238 Ty->getStructElementType(I));
239 ElemTypes.push_back(NewElem);
240 HasChanges |= NewElem.isChanged();
241 }
242 if (!HasChanges) {
243 // we are leaking the created struct here, but there is no way to
244 // correctly delete it
JF 2015/03/08 22:04:38 Missing period
245 return MappingResult(MappedTypes[Ty] = Ty, false);
246 }
247
248 if (StructTy->isLiteral()) {
249 return MappingResult(
250 MappedTypes[Ty] = StructType::get(
251 Ctx, ElemTypes, StructTy->isPacked()),
252 HasChanges);
253 } else {
254 Type* &Loc = MappedTypes[StructTy];
JF 2015/03/08 22:04:38 Ditto on ptr ref.
Mircea Trofin 2015/03/09 21:21:29 Ack, but see the comment before.
255 assert(Loc);
256 StructType *NewStruct = dyn_cast<StructType>(Loc);
257 NewStruct->setBody(ElemTypes, StructTy->isPacked());
258 return MappingResult(MappedTypes[Ty] = NewStruct, true);
259 }
260 }
261
262 // anything else stays the same.
263 return MappingResult(Ty, false);
264 }
265
266 // get the PNaCl-compliant type of a function argument.
267 MappingResult TypeMapper::getCompliantArgumentType(Type *Ty) {
268 // struct registers become pointers to compliant structs
269 if (Ty->isAggregateType()) {
270 return MappingResult(
271 PointerType::get(
272 getCompliantAggregateTypeInternal(Ty), 0),
273 true);
274 }
275
276 return getCompliantAggregateTypeInternal(Ty);
277 }
278
279 // apply 'byval' to func arguments that used to be struct regs.
280 // apply 'sret' to the argument corresponding to the return in the old signature
281 static void ApplyByValAndSRet(Function *OldFunc, Function *NewFunc) {
282 auto const &OldArgList = OldFunc->getArgumentList();
283 auto &NewArgList = NewFunc->getArgumentList();
284
285 // when calling addAttribute, the first one refers to the function, so we
286 // skip past that.
287 unsigned ArgOffset = 1;
288 if (OldFunc->getReturnType()->isAggregateType()) {
289 NewFunc->addAttribute(1, Attribute::AttrKind::StructRet);
290 ArgOffset++;
291 }
292
293 auto NewArg = NewArgList.begin();
294 for (const Argument &OldArg : OldArgList) {
295 if (OldArg.getType()->isAggregateType()) {
296 NewFunc->addAttribute(NewArg->getArgNo() + ArgOffset,
297 Attribute::AttrKind::ByVal);
298 }
299 NewArg++;
300 }
301 }
302
303 // update the arg names for a newly created function
304 static void UpdateArgNames(Function *OldFunc, Function *NewFunc) {
305 auto NewArgIter = NewFunc->arg_begin();
306 auto const &OldFuncArgs = OldFunc->args();
307 if (OldFunc->getReturnType()->isAggregateType()) {
308 NewArgIter->setName("retVal");
309 NewArgIter++;
310 }
311
312 for (const Argument &OldArg : OldFuncArgs) {
313 Argument *NewArg = NewArgIter++;
314 if (OldArg.getType()->isAggregateType()) {
315 NewArg->setName(OldArg.getName() + ".ptr");
316 } else {
317 NewArg->setName(OldArg.getName());
318 }
319 }
320 }
321
322 // replace all uses of an old value with a new one, disregarding the type. We
323 // correct the types separately
324 static void BlindReplace(Value *Old, Value *New) {
325 for (auto UseIter = Old->use_begin(), E = Old->use_end(); E != UseIter;) {
326 Use &AUse = *(UseIter++);
327 AUse.set(New);
328 }
329 }
330
331 // adapt the body of a function for the new arguments
332 static void ConvertArgumentValue(Value *Old,
333 Value *New, Instruction *InsPoint) {
334 if (Old == New)
335 return;
336
337 if (Old->getType() == New->getType()) {
338 Old->replaceAllUsesWith(New);
339 New->takeName(Old);
340 return;
341 }
342
343 if (Old->getType()->isAggregateType() &&
344 New->getType()->isPointerTy()) {
345 Value *Load = new LoadInst(New, Old->getName() + ".sreg", InsPoint);
346 BlindReplace(Old, Load);
347 } else {
348 BlindReplace(Old, New);
349 }
350 }
351
352 // fix returns. Return true if fixes were needed
353 static void FixReturn(Function *OldFunc, Function *NewFunc) {
354
355 Argument *FirstNewArg = NewFunc->getArgumentList().begin();
356
357 for (auto BIter = NewFunc->begin(), LastBlock = NewFunc->end();
358 LastBlock != BIter;) {
359 BasicBlock *BB = BIter++;
360 for (auto IIter = BB->begin(), LastI = BB->end(); LastI != IIter;) {
361 Instruction *Instr = IIter++;
362 if (ReturnInst * Ret = dyn_cast<ReturnInst>(Instr)) {
363 auto &Ctx = Ret->getContext();
364 auto RetVal = Ret->getReturnValue();
365 ReturnInst *NewRet =
366 ReturnInst::Create(Ctx, nullptr, Ret);
367 Ret->eraseFromParent();
368 Ret = nullptr;
369 new StoreInst(RetVal, FirstNewArg, NewRet);
370 }
371 }
372 }
373 }
374
375 template <class TCall>
376 void CopyCallAttributesAndMetadata(TCall* Orig, TCall* NewCall) {
377 NewCall->setCallingConv(Orig->getCallingConv());
378 NewCall->setAttributes(
379 NewCall->getAttributes().addAttributes(Orig->getContext(),
380 AttributeSet::FunctionIndex,
381 Orig->getAttributes().getFnAttributes()));
382 NewCall->setDebugLoc(Orig->getDebugLoc());
383 }
384
385 static InvokeInst *CreateCallFrom(InvokeInst *Orig,
386 Value *Target, ArrayRef<Value*> &Args) {
387 InvokeInst *Ret = InvokeInst::Create(Target,
388 Orig->getNormalDest(), Orig->getUnwindDest(), Args);
389 CopyCallAttributesAndMetadata(Orig, Ret);
390 return Ret;
391 }
392
393 static CallInst *CreateCallFrom(CallInst *Orig,
394 Value *Target, ArrayRef<Value*> &Args) {
395
396 CallInst *Ret = CallInst::Create(Target, Args);
397
398 Ret->setTailCallKind(Orig->getTailCallKind());
399 CopyCallAttributesAndMetadata(Orig, Ret);
400 return Ret;
401 }
402
403 // fix a call site by handing return type changes and/or parameter type and
404 // attribute changes
405 template<class TCall>
406 void NormalizeStructRegSignatures::FixCallSite(TCall *OldCall) {
407 Value *NewTarget = OldCall->getCalledValue();
408
409 if (Function * CalledFunc = dyn_cast<Function>(NewTarget)) {
410 NewTarget = this->FunctionMap[CalledFunc];
411 }
412 assert(NewTarget);
413
414 FunctionType *NewType =
415 dyn_cast<FunctionType>(
416 Mapper.getCompliantType(NewTarget->getType())->
417 getPointerElementType());
418
419 Type *OldRetType = OldCall->getType();
420 const bool isSRet = !OldCall->getType()->isVoidTy() &&
421 NewType->getReturnType()->isVoidTy();
422
423 const unsigned argOffset = isSRet ? 1 : 0;
424
425 SmallVector<Value*, TypicalArity> NewArgs;
426
427 if (isSRet) {
428 AllocaInst *Alloca =
429 new AllocaInst(OldRetType);
430 NewArgs.push_back(Alloca);
431 Alloca->insertBefore(OldCall);
432
433 LoadInst *Load =
434 new LoadInst(Alloca, OldCall->getName() + ".sreg",
435 (Instruction*) nullptr);
436 Load->insertAfter(OldCall);
437 OldCall->replaceAllUsesWith(Load);
438 }
439
440 SmallSetVector<unsigned, TypicalArity> ByRefPlaces;
441
442 for (unsigned ArgPos = 0;
443 ArgPos < NewType->getFunctionNumParams() - argOffset; ArgPos++) {
444
445 Use &OldArgUse = OldCall->getOperandUse(ArgPos);
446 Value *OldArg = OldArgUse;
447 Type *OldArgType = OldArg->getType();
448 unsigned NewArgPos = OldArgUse.getOperandNo() + argOffset;
449 Type *NewArgType = NewType->getFunctionParamType(NewArgPos);
450
451 if (OldArgType != NewArgType && OldArgType->isAggregateType()) {
452 AllocaInst *Alloca =
453 new AllocaInst(OldArgType, OldArg->getName() + ".ptr", OldCall);
454 new StoreInst(OldArg, Alloca, OldCall);
455 ByRefPlaces.insert(NewArgPos);
456 NewArgs.push_back(Alloca);
457 } else {
458 NewArgs.push_back(OldArg);
459 }
460 }
461
462 ArrayRef<Value*> ArrRef = NewArgs;
463 TCall *NewCall = CreateCallFrom(OldCall, NewTarget, ArrRef);
464
465 // copy the attributes over, and add byref/sret as necessary
466 const AttributeSet &OldAttrSet = OldCall->getAttributes();
467 const AttributeSet &NewAttrSet = NewCall->getAttributes();
468 LLVMContext &Ctx = OldCall->getContext();
469 AttrBuilder Builder(OldAttrSet, 0);
470
471 for (unsigned I = 0; I < NewCall->getNumArgOperands(); I++) {
472 NewCall->setAttributes(
473 NewAttrSet.addAttributes(Ctx, I + argOffset + 1,
474 OldAttrSet.getParamAttributes(I + 1)));
475 if (ByRefPlaces.count(I)) {
476 NewCall->addAttribute(I + 1, Attribute::AttrKind::ByVal);
477 }
478 }
479
480 if (isSRet) {
481 NewAttrSet.addAttributes(Ctx, 1, OldAttrSet.getRetAttributes());
482 NewCall->addAttribute(1, Attribute::AttrKind::StructRet);
483 } else {
484 NewCall->setAttributes(
485 NewAttrSet.addAttributes(Ctx,
486 AttributeSet::ReturnIndex, OldAttrSet.getRetAttributes()));
487 // if we still return something, this is the value to replace the old
488 // call with
489 OldCall->replaceAllUsesWith(NewCall);
490 }
491
492 NewCall->insertBefore(OldCall);
493 OldCall->eraseFromParent();
494 OldCall = NULL;
495 }
496
497 void NormalizeStructRegSignatures::ScheduleCallsForCleanup(Function *NewFunc) {
498 for (auto &BBIter : NewFunc->getBasicBlockList()) {
499 for (auto &IIter : BBIter.getInstList()) {
500 if (CallInst * Call = dyn_cast<CallInst>(&IIter)) {
501 CallsToPatch.insert(Call);
502 } else if (InvokeInst * Invoke = dyn_cast<InvokeInst>(&IIter)) {
503 InvokesToPatch.insert(Invoke);
504 }
505 }
506 }
507 }
508
509 // change function body in the light of type changes
510 void NormalizeStructRegSignatures::
511 FixFunctionBody(Function *OldFunc, Function *NewFunc) {
512 if (NewFunc->empty())
513 return;
514
515 bool returnWasFixed = OldFunc->getReturnType()->isAggregateType();
516
517 Instruction *InsPoint = NewFunc->begin()->begin();
518 auto NewArgIter = NewFunc->arg_begin();
519 // advance one more if we used to return a struct register
520 if (returnWasFixed)
521 NewArgIter++;
522
523 // wire new parameters in
524 for (auto ArgIter = OldFunc->arg_begin(), E = OldFunc->arg_end();
525 E != ArgIter;) {
526 Argument *OldArg = ArgIter++;
527 Argument *NewArg = NewArgIter++;
528 ConvertArgumentValue(OldArg, NewArg, InsPoint);
529 }
530
531 // now fix instruction types. Calls are dealt with separately, but we still
532 // update the types here. We know that each value could only possibly be
533 // of a compliant type. At the end of this, call sites will be invalid, but
534 // we handle that afterwards, to make sure we have all the functions changed
535 // first (so that calls have valid targets)
536 for (auto BBIter = NewFunc->begin(), LBlock = NewFunc->end();
537 LBlock != BBIter;) {
538 auto Block = BBIter++;
539 for (auto IIter = Block->begin(), LIns = Block->end(); LIns != IIter;) {
540 auto Instr = IIter++;
541 Instr->mutateType(Mapper.getCompliantType(Instr->getType()));
542 }
543 }
544 if (returnWasFixed)
545 FixReturn(OldFunc, NewFunc);
546 }
547
548 // Ensure function is PNaCl compliant, returning true if the function
549 // changed.
550 bool NormalizeStructRegSignatures::
551 ensurePNaClComplyingFunction(Function *OldFunc, Module &M) {
552 FunctionType *OldFT = OldFunc->getFunctionType();
553 FunctionType *NewFT =
554 dyn_cast<FunctionType>(Mapper.getCompliantType(OldFT));
555 assert(NewFT);
556
557 Function* &AssociatedFctLoc = FunctionMap[OldFunc];
558 if (NewFT != OldFT) {
559 Function *NewFunc = Function::Create(NewFT, OldFunc->getLinkage());
560 AssociatedFctLoc = NewFunc;
561
562 NewFunc->copyAttributesFrom(OldFunc);
563 OldFunc->getParent()->getFunctionList().insert(OldFunc, NewFunc);
564 NewFunc->takeName(OldFunc);
565
566 UpdateArgNames(OldFunc, NewFunc);
567 ApplyByValAndSRet(OldFunc, NewFunc);
568
569 NewFunc->getBasicBlockList().
570 splice(NewFunc->begin(), OldFunc->getBasicBlockList());
571
572 FixFunctionBody(OldFunc, NewFunc);
573 FunctionsToDelete.insert(OldFunc);
574 } else {
575 AssociatedFctLoc = OldFunc;
576 }
577 ScheduleCallsForCleanup(AssociatedFctLoc);
578 return NewFT != OldFT;
579 }
580
581 bool NormalizeStructRegSignatures::runOnModule(Module &M) {
582 bool Changed = false;
583
584 // change function signatures and fix a changed function body by
585 // wiring the new arguments. Call sites are unchanged at this point
586 for (Module::iterator Iter = M.begin(), E = M.end(); Iter != E;) {
587 Function *Func = Iter++;
588 Changed |= ensurePNaClComplyingFunction(Func, M);
589 }
590
591 // fix call sites
592 for (auto &CallToFix : CallsToPatch) {
593 FixCallSite(CallToFix);
594 }
595
596 for (auto &InvokeToFix : InvokesToPatch) {
597 FixCallSite(InvokeToFix);
598 }
599
600 // delete leftover functions - the ones with old signatures
601 for (auto &ToDelete : FunctionsToDelete) {
602 // this also frees the memory
603 ToDelete->eraseFromParent();
604 }
605 return Changed;
606 }
607
608 ModulePass *llvm::createNormalizeStructRegSignaturesPass() {
609 return new NormalizeStructRegSignatures();
610 }
OLDNEW

Powered by Google App Engine