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

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

Issue 939073008: Rebased PNaCl localmods in LLVM to 223109 (Closed)
Patch Set: undo localmod Created 5 years, 9 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
OLDNEW
(Empty)
1 //===- ExpandVarArgs.cpp - Expand out variable argument function calls-----===//
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 pass expands out all use of variable argument functions.
11 //
12 // This pass replaces a varargs function call with a function call in
13 // which a pointer to the variable arguments is passed explicitly.
14 // The callee explicitly allocates space for the variable arguments on
15 // the stack using "alloca".
16 //
17 // Alignment:
18 //
19 // This pass does not add any alignment padding between the arguments
20 // that are copied onto the stack. This means that if the argument
21 // list contains a mixture of, say, 1-byte and 4-byte values, the code
22 // generated by this pass might be inefficient due to the memory
23 // accesses being unaligned.
24 //
25 // This should only be an issue when passing structs as varargs
26 // arguments. We won't see i1, i8, i16 and float as varargs arguments
27 // because the C standard requires the compiler to promote these to
28 // the types "int" and "double".
29 //
30 //===----------------------------------------------------------------------===//
31
32 #include "llvm/ADT/SmallVector.h"
33 #include "llvm/IR/DataLayout.h"
34 #include "llvm/IR/Function.h"
35 #include "llvm/IR/IRBuilder.h"
36 #include "llvm/IR/Instructions.h"
37 #include "llvm/IR/IntrinsicInst.h"
38 #include "llvm/IR/Module.h"
39 #include "llvm/Pass.h"
40 #include "llvm/Transforms/NaCl.h"
41
42 using namespace llvm;
43
44 namespace {
45 // This is a ModulePass because the pass recreates functions in
46 // order to change their argument lists.
47 class ExpandVarArgs : public ModulePass {
48 public:
49 static char ID; // Pass identification, replacement for typeid
50 ExpandVarArgs() : ModulePass(ID) {
51 initializeExpandVarArgsPass(*PassRegistry::getPassRegistry());
52 }
53
54 virtual bool runOnModule(Module &M);
55 };
56 }
57
58 char ExpandVarArgs::ID = 0;
59 INITIALIZE_PASS(ExpandVarArgs, "expand-varargs",
60 "Expand out variable argument function definitions and calls",
61 false, false)
62
63 static void ExpandVarArgFunc(Function *Func) {
64 Type *PtrType = Type::getInt8PtrTy(Func->getContext());
65
66 FunctionType *FTy = Func->getFunctionType();
67 SmallVector<Type *, 8> Params(FTy->param_begin(), FTy->param_end());
68 Params.push_back(PtrType);
69 FunctionType *NFTy = FunctionType::get(FTy->getReturnType(), Params, false);
70 Function *NewFunc = RecreateFunction(Func, NFTy);
71
72 // Declare the new argument as "noalias".
73 NewFunc->setAttributes(
74 Func->getAttributes().addAttribute(
75 Func->getContext(), FTy->getNumParams() + 1, Attribute::NoAlias));
76
77 // Move the arguments across to the new function.
78 for (Function::arg_iterator Arg = Func->arg_begin(), E = Func->arg_end(),
79 NewArg = NewFunc->arg_begin();
80 Arg != E; ++Arg, ++NewArg) {
81 Arg->replaceAllUsesWith(NewArg);
82 NewArg->takeName(Arg);
83 }
84
85 Func->eraseFromParent();
86
87 Value *VarArgsArg = --NewFunc->arg_end();
88 VarArgsArg->setName("varargs");
89
90 // Expand out uses of llvm.va_start in this function.
91 for (Function::iterator BB = NewFunc->begin(), E = NewFunc->end();
92 BB != E;
93 ++BB) {
94 for (BasicBlock::iterator Iter = BB->begin(), E = BB->end();
95 Iter != E; ) {
96 Instruction *Inst = Iter++;
97 if (VAStartInst *VAS = dyn_cast<VAStartInst>(Inst)) {
98 Value *Cast = CopyDebug(new BitCastInst(VAS->getArgList(),
99 PtrType->getPointerTo(),
100 "arglist", VAS), VAS);
101 CopyDebug(new StoreInst(VarArgsArg, Cast, VAS), VAS);
102 VAS->eraseFromParent();
103 }
104 }
105 }
106 }
107
108 static void ExpandVAArgInst(VAArgInst *Inst) {
109 // Read the argument. We assume that no realignment of the pointer
110 // is required.
111 Value *ArgList = CopyDebug(new BitCastInst(
112 Inst->getPointerOperand(),
113 Inst->getType()->getPointerTo()->getPointerTo(), "arglist", Inst), Inst);
114 Value *CurrentPtr = CopyDebug(new LoadInst(ArgList, "arglist_current", Inst),
115 Inst);
116 Value *Result = CopyDebug(new LoadInst(CurrentPtr, "va_arg", Inst), Inst);
117 Result->takeName(Inst);
118
119 // Update the va_list to point to the next argument.
120 SmallVector<Value *, 1> Indexes;
121 Indexes.push_back(ConstantInt::get(Inst->getContext(), APInt(32, 1)));
122 Value *Next = CopyDebug(GetElementPtrInst::Create(
123 CurrentPtr, Indexes, "arglist_next", Inst), Inst);
124 CopyDebug(new StoreInst(Next, ArgList, Inst), Inst);
125
126 Inst->replaceAllUsesWith(Result);
127 Inst->eraseFromParent();
128 }
129
130 static void ExpandVACopyInst(VACopyInst *Inst) {
131 // va_list may have more space reserved, but we only need to
132 // copy a single pointer.
133 Type *PtrTy = Type::getInt8PtrTy(Inst->getContext())->getPointerTo();
134 Value *Src = CopyDebug(new BitCastInst(Inst->getSrc(), PtrTy, "vacopy_src",
135 Inst), Inst);
136 Value *Dest = CopyDebug(new BitCastInst(Inst->getDest(), PtrTy, "vacopy_dest",
137 Inst), Inst);
138 Value *CurrentPtr = CopyDebug(new LoadInst(Src, "vacopy_currentptr", Inst),
139 Inst);
140 CopyDebug(new StoreInst(CurrentPtr, Dest, Inst), Inst);
141 Inst->eraseFromParent();
142 }
143
144 static void LifetimeDecl(Intrinsic::ID id, Value *Ptr, Value *Size,
145 Instruction *InsertPt) {
146 Module *M = InsertPt->getParent()->getParent()->getParent();
147 Value *Func = Intrinsic::getDeclaration(M, id);
148 SmallVector<Value *, 2> Args;
149 Args.push_back(Size);
150 Args.push_back(Ptr);
151 CallInst::Create(Func, Args, "", InsertPt);
152 }
153
154 // CopyCall() uses argument overloading so that it can be used by the
155 // template ExpandVarArgCall().
156 static CallInst *CopyCall(CallInst *Original, Value *Callee,
157 ArrayRef<Value*> Args) {
158 return CallInst::Create(Callee, Args, "", Original);
159 }
160
161 static InvokeInst *CopyCall(InvokeInst *Original, Value *Callee,
162 ArrayRef<Value*> Args) {
163 return InvokeInst::Create(Callee, Original->getNormalDest(),
164 Original->getUnwindDest(), Args, "", Original);
165 }
166
167 // ExpandVarArgCall() converts a CallInst or InvokeInst to expand out
168 // of varargs. It returns whether the module was modified.
169 template <class InstType>
170 static bool ExpandVarArgCall(InstType *Call, DataLayout *DL) {
171 FunctionType *FuncType = cast<FunctionType>(
172 Call->getCalledValue()->getType()->getPointerElementType());
173 if (!FuncType->isFunctionVarArg())
174 return false;
175
176 LLVMContext *Context = &Call->getContext();
177
178 SmallVector<AttributeSet, 8> Attrs;
179 Attrs.push_back(Call->getAttributes().getFnAttributes());
180 Attrs.push_back(Call->getAttributes().getRetAttributes());
181
182 // Split argument list into fixed and variable arguments.
183 SmallVector<Value *, 8> FixedArgs;
184 SmallVector<Value *, 8> VarArgs;
185 SmallVector<Type *, 8> VarArgsTypes;
186 for (unsigned I = 0; I < FuncType->getNumParams(); ++I) {
187 FixedArgs.push_back(Call->getArgOperand(I));
188 // AttributeSets use 1-based indexing.
189 Attrs.push_back(Call->getAttributes().getParamAttributes(I + 1));
190 }
191 for (unsigned I = FuncType->getNumParams();
192 I < Call->getNumArgOperands(); ++I) {
193 Value *ArgVal = Call->getArgOperand(I);
194 VarArgs.push_back(ArgVal);
195 if (Call->getAttributes().hasAttribute(I + 1, Attribute::ByVal)) {
196 // For "byval" arguments we must dereference the pointer.
197 VarArgsTypes.push_back(ArgVal->getType()->getPointerElementType());
198 } else {
199 VarArgsTypes.push_back(ArgVal->getType());
200 }
201 }
202 if (VarArgsTypes.size() == 0) {
203 // Some buggy code (e.g. 176.gcc in Spec2k) uses va_arg on an
204 // empty argument list, which gives undefined behaviour in C. To
205 // work around such programs, we create a dummy varargs buffer on
206 // the stack even though there are no arguments to put in it.
207 // This allows va_arg to read an undefined value from the stack
208 // rather than crashing by reading from an uninitialized pointer.
209 // An alternative would be to pass a null pointer to catch the
210 // invalid use of va_arg.
211 VarArgsTypes.push_back(Type::getInt32Ty(*Context));
212 }
213
214 // Create struct type for packing variable arguments into. We
215 // create this as packed for now and assume that no alignment
216 // padding is desired.
217 StructType *VarArgsTy = StructType::get(*Context, VarArgsTypes, true);
218
219 // Allocate space for the variable argument buffer. Do this at the
220 // start of the function so that we don't leak space if the function
221 // is called in a loop.
222 Function *Func = Call->getParent()->getParent();
223 Instruction *Buf = new AllocaInst(VarArgsTy, "vararg_buffer");
224 Func->getEntryBlock().getInstList().push_front(Buf);
225
226 // Call llvm.lifetime.start/end intrinsics to indicate that Buf is
227 // only used for the duration of the function call, so that the
228 // stack space can be reused elsewhere.
229 Type *I8Ptr = Type::getInt8Ty(*Context)->getPointerTo();
230 Instruction *BufPtr = new BitCastInst(Buf, I8Ptr, "vararg_lifetime_bitcast");
231 BufPtr->insertAfter(Buf);
232 Value *BufSize = ConstantInt::get(*Context,
233 APInt(64, DL->getTypeAllocSize(VarArgsTy)));
234 LifetimeDecl(Intrinsic::lifetime_start, BufPtr, BufSize, Call);
235
236 // Copy variable arguments into buffer.
237 int Index = 0;
238 for (SmallVector<Value *, 8>::iterator Iter = VarArgs.begin();
239 Iter != VarArgs.end();
240 ++Iter, ++Index) {
241 SmallVector<Value *, 2> Indexes;
242 Indexes.push_back(ConstantInt::get(*Context, APInt(32, 0)));
243 Indexes.push_back(ConstantInt::get(*Context, APInt(32, Index)));
244 Value *Ptr = CopyDebug(GetElementPtrInst::Create(
245 Buf, Indexes, "vararg_ptr", Call), Call);
246 if (Call->getAttributes().hasAttribute(
247 FuncType->getNumParams() + Index + 1, Attribute::ByVal)) {
248 IRBuilder<> Builder(Call);
249 Builder.CreateMemCpy(
250 Ptr, *Iter,
251 DL->getTypeAllocSize((*Iter)->getType()->getPointerElementType()),
252 /* Align= */ 1);
253 } else {
254 CopyDebug(new StoreInst(*Iter, Ptr, Call), Call);
255 }
256 }
257
258 // Cast function to new type to add our extra pointer argument.
259 SmallVector<Type *, 8> ArgTypes(FuncType->param_begin(),
260 FuncType->param_end());
261 ArgTypes.push_back(VarArgsTy->getPointerTo());
262 FunctionType *NFTy = FunctionType::get(FuncType->getReturnType(),
263 ArgTypes, false);
264 Value *CastFunc =
265 CopyDebug(new BitCastInst(Call->getCalledValue(), NFTy->getPointerTo(),
266 "vararg_func", Call), Call);
267
268 // Create the converted function call.
269 FixedArgs.push_back(Buf);
270 InstType *NewCall = CopyCall(Call, CastFunc, FixedArgs);
271 CopyDebug(NewCall, Call);
272 NewCall->setAttributes(AttributeSet::get(Call->getContext(), Attrs));
273 NewCall->takeName(Call);
274
275 if (isa<CallInst>(Call)) {
276 LifetimeDecl(Intrinsic::lifetime_end, BufPtr, BufSize, Call);
277 } else if (InvokeInst *Invoke = dyn_cast<InvokeInst>(Call)) {
278 LifetimeDecl(Intrinsic::lifetime_end, BufPtr, BufSize,
279 Invoke->getNormalDest()->getFirstInsertionPt());
280 LifetimeDecl(Intrinsic::lifetime_end, BufPtr, BufSize,
281 Invoke->getUnwindDest()->getFirstInsertionPt());
282 }
283
284 Call->replaceAllUsesWith(NewCall);
285 Call->eraseFromParent();
286
287 return true;
288 }
289
290 bool ExpandVarArgs::runOnModule(Module &M) {
291 bool Changed = false;
292 DataLayout DL(&M);
293
294 for (Module::iterator Iter = M.begin(), E = M.end(); Iter != E; ) {
295 Function *Func = Iter++;
296
297 for (Function::iterator BB = Func->begin(), E = Func->end();
298 BB != E;
299 ++BB) {
300 for (BasicBlock::iterator Iter = BB->begin(), E = BB->end();
301 Iter != E; ) {
302 Instruction *Inst = Iter++;
303 if (VAArgInst *VI = dyn_cast<VAArgInst>(Inst)) {
304 Changed = true;
305 ExpandVAArgInst(VI);
306 } else if (isa<VAEndInst>(Inst)) {
307 // va_end() is a no-op in this implementation.
308 Changed = true;
309 Inst->eraseFromParent();
310 } else if (VACopyInst *VAC = dyn_cast<VACopyInst>(Inst)) {
311 Changed = true;
312 ExpandVACopyInst(VAC);
313 } else if (CallInst *Call = dyn_cast<CallInst>(Inst)) {
314 Changed |= ExpandVarArgCall(Call, &DL);
315 } else if (InvokeInst *Call = dyn_cast<InvokeInst>(Inst)) {
316 Changed |= ExpandVarArgCall(Call, &DL);
317 }
318 }
319 }
320
321 if (Func->isVarArg()) {
322 Changed = true;
323 ExpandVarArgFunc(Func);
324 }
325 }
326
327 return Changed;
328 }
329
330 ModulePass *llvm::createExpandVarArgsPass() {
331 return new ExpandVarArgs();
332 }
OLDNEW
« no previous file with comments | « lib/Transforms/NaCl/ExpandUtils.cpp ('k') | lib/Transforms/NaCl/FixVectorLoadStoreAlignment.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698