Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 7216560

Browse files
author
Mark Seaborn
committed
PNaCl: Add ExpandVarArgs pass for expanding out variable-args function calls
Once this pass is enabled, it will simplify the language to reduce the set of constructs that a PNaCl translator needs to handle as part of a stable wire format for PNaCl. BUG=https://code.google.com/p/nativeclient/issues/detail?id=3338 TEST=test/Transforms/NaCl/expand-varargs.ll Review URL: https://codereview.chromium.org/12481021
1 parent df0539a commit 7216560

File tree

6 files changed

+460
-0
lines changed

6 files changed

+460
-0
lines changed

include/llvm/InitializePasses.h

+1
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ void initializeExpandConstantExprPass(PassRegistry&);
281281
void initializeExpandCtorsPass(PassRegistry&);
282282
void initializeExpandTlsPass(PassRegistry&);
283283
void initializeExpandTlsConstantExprPass(PassRegistry&);
284+
void initializeExpandVarArgsPass(PassRegistry&);
284285
void initializeNaClCcRewritePass(PassRegistry&);
285286
void initializePNaClABIVerifyModulePass(PassRegistry&);
286287
void initializePNaClABIVerifyFunctionsPass(PassRegistry&);

include/llvm/Transforms/NaCl.h

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ FunctionPass *createExpandConstantExprPass();
1919
ModulePass *createExpandCtorsPass();
2020
ModulePass *createExpandTlsPass();
2121
ModulePass *createExpandTlsConstantExprPass();
22+
ModulePass *createExpandVarArgsPass();
2223

2324
}
2425

lib/Transforms/NaCl/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ add_llvm_library(LLVMTransformsNaCl
33
ExpandCtors.cpp
44
ExpandTls.cpp
55
ExpandTlsConstantExpr.cpp
6+
ExpandVarArgs.cpp
67
)
78

89
add_dependencies(LLVMTransformsNaCl intrinsics_gen)

lib/Transforms/NaCl/ExpandVarArgs.cpp

+327
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
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. We assume that the only argument
21+
// types that need to be handled are 32-bit and 64-bit -- i32, i64,
22+
// pointers and double:
23+
//
24+
// * We won't see i1, i8, i16 and float as varargs arguments because
25+
// the C standard requires the compiler to promote these to the
26+
// types "int" and "double".
27+
//
28+
// * We won't see va_arg instructions of struct type because Clang
29+
// does not yet support them in PNaCl mode. See
30+
// https://code.google.com/p/nativeclient/issues/detail?id=2381
31+
//
32+
// If such arguments do appear in the input, this pass will generate
33+
// correct, working code, but this code might be inefficient due to
34+
// using unaligned memory accesses.
35+
//
36+
//===----------------------------------------------------------------------===//
37+
38+
#include "llvm/ADT/SmallVector.h"
39+
#include "llvm/IR/DataLayout.h"
40+
#include "llvm/IR/Function.h"
41+
#include "llvm/IR/Instructions.h"
42+
#include "llvm/IR/IntrinsicInst.h"
43+
#include "llvm/IR/Module.h"
44+
#include "llvm/Pass.h"
45+
#include "llvm/Transforms/NaCl.h"
46+
47+
using namespace llvm;
48+
49+
namespace {
50+
// This is a ModulePass because the pass recreates functions in
51+
// order to change their argument lists.
52+
class ExpandVarArgs : public ModulePass {
53+
public:
54+
static char ID; // Pass identification, replacement for typeid
55+
ExpandVarArgs() : ModulePass(ID) {
56+
initializeExpandVarArgsPass(*PassRegistry::getPassRegistry());
57+
}
58+
59+
virtual bool runOnModule(Module &M);
60+
};
61+
}
62+
63+
char ExpandVarArgs::ID = 0;
64+
INITIALIZE_PASS(ExpandVarArgs, "expand-varargs",
65+
"Expand out variable argument function definitions and calls",
66+
false, false)
67+
68+
static Instruction *CopyDebug(Instruction *NewInst, Instruction *Original) {
69+
NewInst->setDebugLoc(Original->getDebugLoc());
70+
return NewInst;
71+
}
72+
73+
static void ExpandVarArgFunc(Function *Func) {
74+
Type *PtrType = Type::getInt8PtrTy(Func->getContext());
75+
76+
FunctionType *FTy = Func->getFunctionType();
77+
SmallVector<Type *, 8> Params(FTy->param_begin(), FTy->param_end());
78+
Params.push_back(PtrType);
79+
FunctionType *NFTy = FunctionType::get(FTy->getReturnType(), Params, false);
80+
81+
// In order to change the function's arguments, we have to recreate
82+
// the function.
83+
Function *NewFunc = Function::Create(NFTy, Func->getLinkage());
84+
NewFunc->copyAttributesFrom(Func);
85+
Func->getParent()->getFunctionList().insert(Func, NewFunc);
86+
NewFunc->takeName(Func);
87+
NewFunc->getBasicBlockList().splice(NewFunc->begin(),
88+
Func->getBasicBlockList());
89+
90+
// Move the arguments across to the new function.
91+
for (Function::arg_iterator Arg = Func->arg_begin(), E = Func->arg_end(),
92+
NewArg = NewFunc->arg_begin();
93+
Arg != E; ++Arg, ++NewArg) {
94+
Arg->replaceAllUsesWith(NewArg);
95+
NewArg->takeName(Arg);
96+
}
97+
98+
Func->replaceAllUsesWith(
99+
ConstantExpr::getBitCast(NewFunc, FTy->getPointerTo()));
100+
Func->eraseFromParent();
101+
102+
Value *VarArgsArg = --NewFunc->arg_end();
103+
VarArgsArg->setName("varargs");
104+
105+
// Expand out uses of llvm.va_start in this function.
106+
for (Function::iterator BB = NewFunc->begin(), E = NewFunc->end();
107+
BB != E;
108+
++BB) {
109+
for (BasicBlock::iterator Iter = BB->begin(), E = BB->end();
110+
Iter != E; ) {
111+
Instruction *Inst = Iter++;
112+
if (VAStartInst *VAS = dyn_cast<VAStartInst>(Inst)) {
113+
Value *Cast = CopyDebug(new BitCastInst(VAS->getArgList(),
114+
PtrType->getPointerTo(),
115+
"arglist", VAS), VAS);
116+
CopyDebug(new StoreInst(VarArgsArg, Cast, VAS), VAS);
117+
VAS->eraseFromParent();
118+
}
119+
}
120+
}
121+
}
122+
123+
static void ExpandVAArgInst(VAArgInst *Inst) {
124+
// Read the argument. We assume that no realignment of the pointer
125+
// is required.
126+
Value *ArgList = CopyDebug(new BitCastInst(
127+
Inst->getPointerOperand(),
128+
Inst->getType()->getPointerTo()->getPointerTo(), "arglist", Inst), Inst);
129+
Value *CurrentPtr = CopyDebug(new LoadInst(ArgList, "arglist_current", Inst),
130+
Inst);
131+
Value *Result = CopyDebug(new LoadInst(CurrentPtr, "va_arg", Inst), Inst);
132+
Result->takeName(Inst);
133+
134+
// Update the va_list to point to the next argument.
135+
SmallVector<Value *, 1> Indexes;
136+
Indexes.push_back(ConstantInt::get(Inst->getContext(), APInt(32, 1)));
137+
Value *Next = CopyDebug(GetElementPtrInst::Create(
138+
CurrentPtr, Indexes, "arglist_next", Inst), Inst);
139+
CopyDebug(new StoreInst(Next, ArgList, Inst), Inst);
140+
141+
Inst->replaceAllUsesWith(Result);
142+
Inst->eraseFromParent();
143+
}
144+
145+
static void ExpandVACopyInst(VACopyInst *Inst) {
146+
// va_list may have more space reserved, but we only need to
147+
// copy a single pointer.
148+
Type *PtrTy = Type::getInt8PtrTy(Inst->getContext())->getPointerTo();
149+
Value *Src = CopyDebug(new BitCastInst(Inst->getSrc(), PtrTy, "vacopy_src",
150+
Inst), Inst);
151+
Value *Dest = CopyDebug(new BitCastInst(Inst->getDest(), PtrTy, "vacopy_dest",
152+
Inst), Inst);
153+
Value *CurrentPtr = CopyDebug(new LoadInst(Src, "vacopy_currentptr", Inst),
154+
Inst);
155+
CopyDebug(new StoreInst(CurrentPtr, Dest, Inst), Inst);
156+
Inst->eraseFromParent();
157+
}
158+
159+
static void LifetimeDecl(Intrinsic::ID id, Value *Ptr, Value *Size,
160+
Instruction *InsertPt) {
161+
Module *M = InsertPt->getParent()->getParent()->getParent();
162+
Value *Func = Intrinsic::getDeclaration(M, id);
163+
SmallVector<Value *, 2> Args;
164+
Args.push_back(Size);
165+
Args.push_back(Ptr);
166+
CallInst::Create(Func, Args, "", InsertPt);
167+
}
168+
169+
// CopyCall() uses argument overloading so that it can be used by the
170+
// template ExpandVarArgCall().
171+
static Instruction *CopyCall(CallInst *Original, Value *Callee,
172+
ArrayRef<Value*> Args) {
173+
return CallInst::Create(Callee, Args, "", Original);
174+
}
175+
176+
static Instruction *CopyCall(InvokeInst *Original, Value *Callee,
177+
ArrayRef<Value*> Args) {
178+
return InvokeInst::Create(Callee, Original->getNormalDest(),
179+
Original->getUnwindDest(), Args, "", Original);
180+
}
181+
182+
// ExpandVarArgCall() converts a CallInst or InvokeInst to expand out
183+
// of varargs. It returns whether the module was modified.
184+
template <class InstType>
185+
static bool ExpandVarArgCall(InstType *Call, DataLayout *DL) {
186+
FunctionType *FuncType = cast<FunctionType>(
187+
Call->getCalledValue()->getType()->getPointerElementType());
188+
if (!FuncType->isFunctionVarArg())
189+
return false;
190+
191+
LLVMContext *Context = &Call->getContext();
192+
193+
// Split argument list into fixed and variable arguments.
194+
SmallVector<Value *, 8> FixedArgs;
195+
SmallVector<Value *, 8> VarArgs;
196+
SmallVector<Type *, 8> VarArgsTypes;
197+
for (unsigned I = 0; I < FuncType->getNumParams(); ++I)
198+
FixedArgs.push_back(Call->getArgOperand(I));
199+
for (unsigned I = FuncType->getNumParams();
200+
I < Call->getNumArgOperands(); ++I) {
201+
VarArgs.push_back(Call->getArgOperand(I));
202+
VarArgsTypes.push_back(Call->getArgOperand(I)->getType());
203+
}
204+
205+
StructType *VarArgsTy;
206+
Value *ArgToAdd;
207+
Instruction *BufPtr = NULL;
208+
Value *BufSize = NULL;
209+
if (VarArgs.size() == 0) {
210+
// If there are no variable arguments being passed, we still want
211+
// to add an extra argument to the function call so that the
212+
// number of arguments matches the callee's type.
213+
VarArgsTy = StructType::get(*Context);
214+
ArgToAdd = UndefValue::get(VarArgsTy->getPointerTo());
215+
} else {
216+
// Create struct type for packing variable arguments into. We
217+
// create this as packed for now and assume that no alignment
218+
// padding is desired.
219+
VarArgsTy = StructType::create(VarArgsTypes, "vararg_call", true);
220+
221+
// Allocate space for the variable argument buffer. Do this at the
222+
// start of the function so that we don't leak space if the function
223+
// is called in a loop.
224+
Function *Func = Call->getParent()->getParent();
225+
Instruction *Buf = new AllocaInst(VarArgsTy, "vararg_buffer");
226+
Func->getEntryBlock().getInstList().push_front(Buf);
227+
ArgToAdd = Buf;
228+
229+
// Call llvm.lifetime.start/end intrinsics to indicate that Buf is
230+
// only used for the duration of the function call, so that the
231+
// stack space can be reused elsewhere.
232+
Type *I8Ptr = Type::getInt8Ty(*Context)->getPointerTo();
233+
BufPtr = new BitCastInst(Buf, I8Ptr, "vararg_lifetime_bitcast");
234+
BufPtr->insertAfter(Buf);
235+
BufSize = ConstantInt::get(*Context,
236+
APInt(64, DL->getTypeAllocSize(VarArgsTy)));
237+
LifetimeDecl(Intrinsic::lifetime_start, BufPtr, BufSize, Call);
238+
239+
// Copy variable arguments into buffer.
240+
int Index = 0;
241+
for (SmallVector<Value *, 8>::iterator Iter = VarArgs.begin();
242+
Iter != VarArgs.end();
243+
++Iter, ++Index) {
244+
SmallVector<Value *, 2> Indexes;
245+
Indexes.push_back(ConstantInt::get(*Context, APInt(32, 0)));
246+
Indexes.push_back(ConstantInt::get(*Context, APInt(32, Index)));
247+
Value *Ptr = CopyDebug(GetElementPtrInst::Create(
248+
Buf, Indexes, "vararg_ptr", Call), Call);
249+
CopyDebug(new StoreInst(*Iter, Ptr, Call), Call);
250+
}
251+
}
252+
253+
// Cast function to new type to add our extra pointer argument.
254+
SmallVector<Type *, 8> ArgTypes(FuncType->param_begin(),
255+
FuncType->param_end());
256+
ArgTypes.push_back(VarArgsTy->getPointerTo());
257+
FunctionType *NFTy = FunctionType::get(FuncType->getReturnType(),
258+
ArgTypes, false);
259+
Value *CastFunc =
260+
CopyDebug(new BitCastInst(Call->getCalledValue(), NFTy->getPointerTo(),
261+
"vararg_func", Call), Call);
262+
263+
// Create the converted function call.
264+
FixedArgs.push_back(ArgToAdd);
265+
Value *NewCall = CopyDebug(CopyCall(Call, CastFunc, FixedArgs), Call);
266+
NewCall->takeName(Call);
267+
268+
if (BufPtr) {
269+
if (isa<CallInst>(Call)) {
270+
LifetimeDecl(Intrinsic::lifetime_end, BufPtr, BufSize, Call);
271+
} else if (InvokeInst *Invoke = dyn_cast<InvokeInst>(Call)) {
272+
LifetimeDecl(Intrinsic::lifetime_end, BufPtr, BufSize,
273+
Invoke->getNormalDest()->getFirstInsertionPt());
274+
LifetimeDecl(Intrinsic::lifetime_end, BufPtr, BufSize,
275+
Invoke->getUnwindDest()->getFirstInsertionPt());
276+
}
277+
}
278+
279+
Call->replaceAllUsesWith(NewCall);
280+
Call->eraseFromParent();
281+
282+
return true;
283+
}
284+
285+
bool ExpandVarArgs::runOnModule(Module &M) {
286+
bool Changed = false;
287+
DataLayout DL(&M);
288+
289+
for (Module::iterator Iter = M.begin(), E = M.end(); Iter != E; ) {
290+
Function *Func = Iter++;
291+
292+
for (Function::iterator BB = Func->begin(), E = Func->end();
293+
BB != E;
294+
++BB) {
295+
for (BasicBlock::iterator Iter = BB->begin(), E = BB->end();
296+
Iter != E; ) {
297+
Instruction *Inst = Iter++;
298+
if (VAArgInst *VI = dyn_cast<VAArgInst>(Inst)) {
299+
Changed = true;
300+
ExpandVAArgInst(VI);
301+
} else if (isa<VAEndInst>(Inst)) {
302+
// va_end() is a no-op in this implementation.
303+
Changed = true;
304+
Inst->eraseFromParent();
305+
} else if (VACopyInst *VAC = dyn_cast<VACopyInst>(Inst)) {
306+
Changed = true;
307+
ExpandVACopyInst(VAC);
308+
} else if (CallInst *Call = dyn_cast<CallInst>(Inst)) {
309+
Changed |= ExpandVarArgCall(Call, &DL);
310+
} else if (InvokeInst *Call = dyn_cast<InvokeInst>(Inst)) {
311+
Changed |= ExpandVarArgCall(Call, &DL);
312+
}
313+
}
314+
}
315+
316+
if (Func->isVarArg()) {
317+
Changed = true;
318+
ExpandVarArgFunc(Func);
319+
}
320+
}
321+
322+
return Changed;
323+
}
324+
325+
ModulePass *llvm::createExpandVarArgsPass() {
326+
return new ExpandVarArgs();
327+
}

0 commit comments

Comments
 (0)