Chromium Code Reviews| OLD | NEW | 
|---|---|
| (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. 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 <vector> | |
| 39 | |
| 40 #include "llvm/IR/DataLayout.h" | |
| 41 #include "llvm/IR/Function.h" | |
| 42 #include "llvm/IR/Instructions.h" | |
| 43 #include "llvm/IR/IntrinsicInst.h" | |
| 44 #include "llvm/IR/Module.h" | |
| 45 #include "llvm/Pass.h" | |
| 46 #include "llvm/Transforms/NaCl.h" | |
| 47 | |
| 48 using namespace llvm; | |
| 49 | |
| 50 namespace { | |
| 51 class ExpandVarArgs : public ModulePass { | |
| 52 public: | |
| 53 static char ID; // Pass identification, replacement for typeid | |
| 54 ExpandVarArgs() : ModulePass(ID) { | |
| 55 initializeExpandVarArgsPass(*PassRegistry::getPassRegistry()); | |
| 56 } | |
| 57 | |
| 58 virtual bool runOnModule(Module &M); | |
| 59 }; | |
| 60 } | |
| 61 | |
| 62 char ExpandVarArgs::ID = 0; | |
| 63 INITIALIZE_PASS(ExpandVarArgs, "expand-varargs", | |
| 64 "Expand out variable argument function definitions and calls", | |
| 65 false, false) | |
| 66 | |
| 67 static void ExpandVarArgFunc(Function *Func) { | |
| 
 
eliben
2013/03/21 16:10:11
Since you only call this from runOnModule, why not
 
Mark Seaborn
2013/03/21 18:07:55
Using getParent() seems to be idiomatic in LLVM.
 
eliben
2013/03/21 18:36:40
Alas, LLVM is full of cargo-cult programming so gr
 
 | |
| 68 Module *Module = Func->getParent(); | |
| 69 Type *PtrType = Type::getInt8Ty(Module->getContext())->getPointerTo(); | |
| 
 
eliben
2013/03/21 16:10:11
Type::getInt8PtrTy
 
Mark Seaborn
2013/03/21 18:07:55
Done.
 
 | |
| 70 | |
| 71 FunctionType *FTy = Func->getFunctionType(); | |
| 72 std::vector<Type*> Params(FTy->param_begin(), FTy->param_end()); | |
| 
 
eliben
2013/03/21 16:10:11
Did you consider SmallVector? It can be more effic
 
Mark Seaborn
2013/03/21 18:07:55
Done.
 
 | |
| 73 Params.push_back(PtrType); | |
| 74 FunctionType *NFTy = FunctionType::get(FTy->getReturnType(), Params, false); | |
| 75 | |
| 76 // In order to change the function's arguments, we have to recreate | |
| 77 // the function. | |
| 78 Function *NewFunc = Function::Create(NFTy, Func->getLinkage()); | |
| 79 NewFunc->copyAttributesFrom(Func); | |
| 80 Func->getParent()->getFunctionList().insert(Func, NewFunc); | |
| 
 
eliben
2013/03/21 16:10:11
Again, would be nice to just have a Module* here i
 
Mark Seaborn
2013/03/21 18:07:55
I don't think that's idiomatic.  Note that I based
 
 | |
| 81 NewFunc->takeName(Func); | |
| 82 NewFunc->getBasicBlockList().splice(NewFunc->begin(), | |
| 83 Func->getBasicBlockList()); | |
| 84 | |
| 85 // Move the arguments across to the new function. | |
| 86 for (Function::arg_iterator Arg = Func->arg_begin(), E = Func->arg_end(), | |
| 87 NewArg = NewFunc->arg_begin(); | |
| 88 Arg != E; ++Arg, ++NewArg) { | |
| 89 Arg->replaceAllUsesWith(NewArg); | |
| 90 NewArg->takeName(Arg); | |
| 91 } | |
| 92 | |
| 93 Func->replaceAllUsesWith( | |
| 
 
eliben
2013/03/21 16:10:11
Would it also be useful to preserve the debug info
 
Mark Seaborn
2013/03/21 18:07:55
Yes; I'll have to investigate this.
 
Mark Seaborn
2013/03/21 19:50:54
AFAICT, replaceAllUsesWith() preserves the debug m
 
 | |
| 94 ConstantExpr::getBitCast(NewFunc, FTy->getPointerTo())); | |
| 95 Func->eraseFromParent(); | |
| 96 | |
| 97 Value *VarArgsArg = --NewFunc->arg_end(); | |
| 98 VarArgsArg->setName("varargs"); | |
| 99 | |
| 100 // Expand out uses of llvm.va_start in this function. | |
| 101 for (Function::iterator BB = NewFunc->begin(), E = NewFunc->end(); | |
| 102 BB != E; | |
| 103 ++BB) { | |
| 104 for (BasicBlock::iterator Iter = BB->begin(), E = BB->end(); | |
| 105 Iter != E; ) { | |
| 106 Instruction *Inst = Iter++; | |
| 107 if (VAStartInst *VAS = dyn_cast<VAStartInst>(Inst)) { | |
| 108 Value *Cast = new BitCastInst(VAS->getArgList(), | |
| 109 PtrType->getPointerTo(), | |
| 110 "arglist", VAS); | |
| 111 new StoreInst(VarArgsArg, Cast, VAS); | |
| 112 VAS->eraseFromParent(); | |
| 113 } | |
| 114 } | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 static void ExpandVAArgInst(VAArgInst *Inst) { | |
| 119 Module *Module = Inst->getParent()->getParent()->getParent(); | |
| 
 
eliben
2013/03/21 16:10:11
Here it's probably even better reason to pass Modu
 
Mark Seaborn
2013/03/21 18:07:55
Cleaned up to use Inst->getContext().
 
 | |
| 120 LLVMContext *Context = &Module->getContext(); | |
| 121 | |
| 122 // Read the argument. We assume that no realignment of the pointer | |
| 123 // is required. | |
| 124 Value *ArgList = new BitCastInst( | |
| 125 Inst->getPointerOperand(), | |
| 126 Inst->getType()->getPointerTo()->getPointerTo(), "arglist", Inst); | |
| 127 Value *CurrentPtr = new LoadInst(ArgList, "arglist_current", Inst); | |
| 128 Value *Result = new LoadInst(CurrentPtr, "va_arg", Inst); | |
| 129 Result->takeName(Inst); | |
| 130 | |
| 131 // Update the va_list to point to the next argument. | |
| 132 std::vector<Value*> Indexes; | |
| 133 Indexes.push_back(ConstantInt::get(*Context, APInt(32, 1))); | |
| 134 Value *Next = GetElementPtrInst::Create(CurrentPtr, Indexes, | |
| 
 
eliben
2013/03/21 16:10:11
Is it worthwhile to create such a GEP if you're go
 
Mark Seaborn
2013/03/21 18:07:55
It's certainly easier to use GEP and have a later
 
 | |
| 135 "arglist_next", Inst); | |
| 136 new StoreInst(Next, ArgList, Inst); | |
| 137 | |
| 138 Inst->replaceAllUsesWith(Result); | |
| 139 Inst->eraseFromParent(); | |
| 140 } | |
| 141 | |
| 142 static void ExpandVACopyInst(VACopyInst *Inst, Module *M) { | |
| 143 // va_list may have more space reserved, but we only need to | |
| 144 // copy a single pointer. | |
| 145 Type *I8 = Type::getInt8Ty(M->getContext()); | |
| 146 Type *PtrTy = I8->getPointerTo()->getPointerTo(); | |
| 147 Value *Src = new BitCastInst(Inst->getSrc(), PtrTy, "vacopy_src", Inst); | |
| 148 Value *Dest = new BitCastInst(Inst->getDest(), PtrTy, "vacopy_dest", Inst); | |
| 149 Value *CurrentPtr = new LoadInst(Src, "vacopy_currentptr", Inst); | |
| 150 new StoreInst(CurrentPtr, Dest, Inst); | |
| 151 Inst->eraseFromParent(); | |
| 152 } | |
| 153 | |
| 154 static void LifetimeDecl(Intrinsic::ID id, Value *Ptr, Value *Size, | |
| 155 Instruction *InsertPt) { | |
| 156 Module *M = InsertPt->getParent()->getParent()->getParent(); | |
| 157 Value *Func = Intrinsic::getDeclaration(M, id); | |
| 158 std::vector<Value*> Args; | |
| 
 
eliben
2013/03/21 16:10:11
Here and elsewhere, use SmallVector. It was create
 
Mark Seaborn
2013/03/21 18:07:55
Done.
 
 | |
| 159 Args.push_back(Size); | |
| 160 Args.push_back(Ptr); | |
| 161 CallInst::Create(Func, Args, "", InsertPt); | |
| 162 } | |
| 163 | |
| 164 // CopyCall() uses argument overloading so that it can be used by the | |
| 165 // template ExpandVarArgCall(). | |
| 166 static Instruction *CopyCall(CallInst *Original, Value *Callee, | |
| 167 ArrayRef<Value*> Args) { | |
| 168 return CallInst::Create(Callee, Args, "", Original); | |
| 169 } | |
| 170 | |
| 171 static Instruction *CopyCall(InvokeInst *Original, Value *Callee, | |
| 172 ArrayRef<Value*> Args) { | |
| 173 return InvokeInst::Create(Callee, Original->getNormalDest(), | |
| 174 Original->getUnwindDest(), Args, "", Original); | |
| 175 } | |
| 176 | |
| 177 template <class InstType> | |
| 178 static bool ExpandVarArgCall(InstType *Call, DataLayout *DL) { | |
| 
 
eliben
2013/03/21 16:10:11
Please add a comment explaining what this does
 
Mark Seaborn
2013/03/21 18:07:55
Done.
 
 | |
| 179 FunctionType *FuncType = cast<FunctionType>( | |
| 180 Call->getCalledValue()->getType()->getPointerElementType()); | |
| 181 if (!FuncType->isFunctionVarArg()) | |
| 182 return false; | |
| 183 | |
| 184 LLVMContext *Context = | |
| 185 &Call->getParent()->getParent()->getParent()->getContext(); | |
| 186 | |
| 187 // Split argument list into fixed and variable arguments. | |
| 188 std::vector<Value*> FixedArgs; | |
| 189 std::vector<Value*> VarArgs; | |
| 190 std::vector<Type*> VarArgsTypes; | |
| 191 for (unsigned I = 0; I < FuncType->getNumParams(); ++I) | |
| 192 FixedArgs.push_back(Call->getArgOperand(I)); | |
| 193 for (unsigned I = FuncType->getNumParams(); | |
| 194 I < Call->getNumArgOperands(); ++I) { | |
| 195 VarArgs.push_back(Call->getArgOperand(I)); | |
| 196 VarArgsTypes.push_back(Call->getArgOperand(I)->getType()); | |
| 197 } | |
| 198 | |
| 199 StructType *VarArgsTy; | |
| 200 Value *ArgToAdd; | |
| 201 Instruction *BufPtr = NULL; | |
| 202 Value *BufSize = NULL; | |
| 203 if (VarArgs.size() == 0) { | |
| 204 // If there are no variable arguments being passed, we still want | |
| 205 // to add an extra argument to the function call so that the | |
| 206 // number of arguments matches the callee's type. | |
| 207 VarArgsTy = StructType::get(*Context); | |
| 208 ArgToAdd = UndefValue::get(VarArgsTy->getPointerTo()); | |
| 209 } else { | |
| 210 // Create struct type for packing variable arguments into. We | |
| 211 // create this as packed for now and assume that no alignment | |
| 212 // padding is desired. | |
| 213 VarArgsTy = StructType::create(VarArgsTypes, "vararg_call", true); | |
| 214 | |
| 215 // Allocate space for the variable argument buffer. Do this at the | |
| 216 // start of the function so that we don't leak space if the function | |
| 217 // is called in a loop. | |
| 218 Function *Func = Call->getParent()->getParent(); | |
| 219 Instruction *Buf = new AllocaInst(VarArgsTy, "vararg_buffer"); | |
| 220 Func->getEntryBlock().getInstList().push_front(Buf); | |
| 221 ArgToAdd = Buf; | |
| 222 | |
| 223 // Call llvm.lifetime.start/end intrinsics to indicate that Buf is | |
| 224 // only used for the duration of the function call, so that the | |
| 225 // stack space can be reused elsewhere. | |
| 226 Type *I8Ptr = Type::getInt8Ty(*Context)->getPointerTo(); | |
| 227 BufPtr = new BitCastInst(Buf, I8Ptr, "vararg_lifetime_bitcast"); | |
| 228 BufPtr->insertAfter(Buf); | |
| 229 BufSize = ConstantInt::get(*Context, | |
| 230 APInt(64, DL->getTypeAllocSize(VarArgsTy))); | |
| 
 
eliben
2013/03/21 16:10:11
I'm not sure you need APInts  here and elsewhere.
 
Mark Seaborn
2013/03/21 18:07:55
There are two ways of creating an i64 ConstantInt:
 
eliben
2013/03/21 18:36:40
I initially thought that precomputing all useful t
 
 | |
| 231 LifetimeDecl(Intrinsic::lifetime_start, BufPtr, BufSize, Call); | |
| 232 | |
| 233 // Copy variable arguments into buffer. | |
| 234 int Index = 0; | |
| 235 for (std::vector<Value*>::iterator Iter = VarArgs.begin(); | |
| 236 Iter != VarArgs.end(); | |
| 237 ++Iter, ++Index) { | |
| 238 std::vector<Value*> Indexes; | |
| 239 Indexes.push_back(ConstantInt::get(*Context, APInt(32, 0))); | |
| 240 Indexes.push_back(ConstantInt::get(*Context, APInt(32, Index))); | |
| 241 Value *Ptr = GetElementPtrInst::Create(Buf, Indexes, "vararg_ptr", Call); | |
| 242 new StoreInst(*Iter, Ptr, Call); | |
| 243 } | |
| 244 } | |
| 245 | |
| 246 // Cast function to new type to add our extra pointer argument. | |
| 247 std::vector<Type*> ArgTypes(FuncType->param_begin(), FuncType->param_end()); | |
| 248 ArgTypes.push_back(VarArgsTy->getPointerTo()); | |
| 249 FunctionType *NFTy = FunctionType::get(FuncType->getReturnType(), | |
| 250 ArgTypes, false); | |
| 251 Value *CastFunc = new BitCastInst(Call->getCalledValue(), | |
| 252 NFTy->getPointerTo(), "vararg_func", Call); | |
| 253 | |
| 254 // Create the converted function call. | |
| 255 FixedArgs.push_back(ArgToAdd); | |
| 256 Value *NewCall = CopyCall(Call, CastFunc, FixedArgs); | |
| 257 NewCall->takeName(Call); | |
| 258 | |
| 259 if (BufPtr) { | |
| 260 if (isa<CallInst>(Call)) { | |
| 261 LifetimeDecl(Intrinsic::lifetime_end, BufPtr, BufSize, Call); | |
| 262 } else if (InvokeInst *Invoke = dyn_cast<InvokeInst>(Call)) { | |
| 263 LifetimeDecl(Intrinsic::lifetime_end, BufPtr, BufSize, | |
| 264 Invoke->getNormalDest()->getFirstInsertionPt()); | |
| 265 LifetimeDecl(Intrinsic::lifetime_end, BufPtr, BufSize, | |
| 266 Invoke->getUnwindDest()->getFirstInsertionPt()); | |
| 267 } | |
| 268 } | |
| 269 | |
| 270 Call->replaceAllUsesWith(NewCall); | |
| 271 Call->eraseFromParent(); | |
| 272 | |
| 273 return true; | |
| 274 } | |
| 275 | |
| 276 bool ExpandVarArgs::runOnModule(Module &M) { | |
| 277 bool Changed = false; | |
| 278 DataLayout DL(&M); | |
| 279 | |
| 280 for (Module::iterator Iter = M.begin(), E = M.end(); Iter != E; ) { | |
| 281 Function *Func = Iter++; | |
| 282 | |
| 283 for (Function::iterator BB = Func->begin(), E = Func->end(); | |
| 284 BB != E; | |
| 285 ++BB) { | |
| 286 for (BasicBlock::iterator Iter = BB->begin(), E = BB->end(); | |
| 287 Iter != E; ) { | |
| 288 Instruction *Inst = Iter++; | |
| 289 if (VAArgInst *VI = dyn_cast<VAArgInst>(Inst)) { | |
| 290 Changed = true; | |
| 291 ExpandVAArgInst(VI); | |
| 292 } else if (isa<VAEndInst>(Inst)) { | |
| 293 // va_end() is a no-op in this implementation. | |
| 294 Changed = true; | |
| 295 Inst->eraseFromParent(); | |
| 296 } else if (VACopyInst *VAC = dyn_cast<VACopyInst>(Inst)) { | |
| 297 Changed = true; | |
| 298 ExpandVACopyInst(VAC, &M); | |
| 299 } else if (CallInst *Call = dyn_cast<CallInst>(Inst)) { | |
| 300 Changed |= ExpandVarArgCall(Call, &DL); | |
| 301 } else if (InvokeInst *Call = dyn_cast<InvokeInst>(Inst)) { | |
| 302 Changed |= ExpandVarArgCall(Call, &DL); | |
| 303 } | |
| 304 } | |
| 305 } | |
| 306 | |
| 307 if (Func->isVarArg()) { | |
| 308 Changed = true; | |
| 309 ExpandVarArgFunc(Func); | |
| 310 } | |
| 311 } | |
| 312 | |
| 313 return Changed; | |
| 314 } | |
| 315 | |
| 316 ModulePass *llvm::createExpandVarArgsPass() { | |
| 317 return new ExpandVarArgs(); | |
| 318 } | |
| OLD | NEW |