|
| 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