|
| 1 | + |
| 2 | +#include "expand_varargs.h" |
| 3 | + |
| 4 | +#include <llvm/BasicBlock.h> |
| 5 | +#include <llvm/Constants.h> |
| 6 | +#include <llvm/Function.h> |
| 7 | +#include <llvm/InstrTypes.h> |
| 8 | +#include <llvm/Instructions.h> |
| 9 | +#include <llvm/IntrinsicInst.h> |
| 10 | +#include <llvm/Module.h> |
| 11 | +#include <llvm/Pass.h> |
| 12 | + |
| 13 | +// In LLVM 3.2, this becomes <llvm/DataLayout.h> |
| 14 | +#include <llvm/Target/TargetData.h> |
| 15 | + |
| 16 | +using namespace llvm; |
| 17 | + |
| 18 | +namespace { |
| 19 | + class ExpandVarArgs : public ModulePass { |
| 20 | + public: |
| 21 | + static char ID; // Pass identification, replacement for typeid |
| 22 | + ExpandVarArgs() : ModulePass(ID) { |
| 23 | + } |
| 24 | + |
| 25 | + virtual bool runOnModule(Module &M); |
| 26 | + }; |
| 27 | +} |
| 28 | + |
| 29 | +char ExpandVarArgs::ID = 0; |
| 30 | + |
| 31 | +static void ExpandVarArgFunc(Function *Func) { |
| 32 | + Module *Module = Func->getParent(); |
| 33 | + Type *PtrType = Type::getInt8Ty(Module->getContext())->getPointerTo(); |
| 34 | + |
| 35 | + FunctionType *FTy = Func->getFunctionType(); |
| 36 | + std::vector<Type*> Params(FTy->param_begin(), FTy->param_end()); |
| 37 | + Params.push_back(PtrType); |
| 38 | + FunctionType *NFTy = FunctionType::get(FTy->getReturnType(), Params, false); |
| 39 | + |
| 40 | + // In order to change the function's arguments, we have to recreate |
| 41 | + // the function. |
| 42 | + Function *NewFunc = Function::Create(NFTy, Func->getLinkage()); |
| 43 | + NewFunc->copyAttributesFrom(Func); |
| 44 | + Func->getParent()->getFunctionList().insert(Func, NewFunc); |
| 45 | + NewFunc->takeName(Func); |
| 46 | + NewFunc->getBasicBlockList().splice(NewFunc->begin(), |
| 47 | + Func->getBasicBlockList()); |
| 48 | + |
| 49 | + // Move the arguments across to the new function. |
| 50 | + for (Function::arg_iterator Arg = Func->arg_begin(), E = Func->arg_end(), |
| 51 | + NewArg = NewFunc->arg_begin(); |
| 52 | + Arg != E; ++Arg, ++NewArg) { |
| 53 | + Arg->replaceAllUsesWith(NewArg); |
| 54 | + NewArg->takeName(Arg); |
| 55 | + } |
| 56 | + |
| 57 | + Func->replaceAllUsesWith( |
| 58 | + ConstantExpr::getBitCast(NewFunc, FTy->getPointerTo())); |
| 59 | + Func->eraseFromParent(); |
| 60 | + |
| 61 | + Value *VarArgsArg = --NewFunc->arg_end(); |
| 62 | + VarArgsArg->setName("varargs"); |
| 63 | + |
| 64 | + for (Function::iterator BB = NewFunc->begin(), E = NewFunc->end(); |
| 65 | + BB != E; |
| 66 | + ++BB) { |
| 67 | + for (BasicBlock::iterator Iter = BB->begin(), E = BB->end(); |
| 68 | + Iter != E; ) { |
| 69 | + Instruction *Inst = Iter++; |
| 70 | + // TODO: Use VAStartInst when we upgrade LLVM version. |
| 71 | + if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(Inst)) { |
| 72 | + if (II->getIntrinsicID() == Intrinsic::vastart) { |
| 73 | + Value *Cast = new BitCastInst(II->getOperand(0), |
| 74 | + PtrType->getPointerTo(), |
| 75 | + "arglist", II); |
| 76 | + new StoreInst(VarArgsArg, Cast, II); |
| 77 | + II->eraseFromParent(); |
| 78 | + } else if (II->getIntrinsicID() == Intrinsic::vaend) { |
| 79 | + II->eraseFromParent(); |
| 80 | + } |
| 81 | + } |
| 82 | + } |
| 83 | + } |
| 84 | + |
| 85 | + // TODO: Update debug information too. |
| 86 | +} |
| 87 | + |
| 88 | +static void ExpandVAArgInst(VAArgInst *Inst, TargetData *DataLayout) { |
| 89 | + Module *Module = Inst->getParent()->getParent()->getParent(); |
| 90 | + Type *I8 = Type::getInt8Ty(Module->getContext()); |
| 91 | + Type *I32 = Type::getInt32Ty(Module->getContext()); |
| 92 | + |
| 93 | + // Read the argument. |
| 94 | + Value *ArgList = new BitCastInst(Inst->getPointerOperand(), |
| 95 | + I8->getPointerTo()->getPointerTo(), |
| 96 | + "arglist", Inst); |
| 97 | + Value *CurrentPtr = new LoadInst(ArgList, "arglist_current", Inst); |
| 98 | + Value *Result = |
| 99 | + new LoadInst(new BitCastInst(CurrentPtr, Inst->getType()->getPointerTo(), |
| 100 | + "va_arg_ptr", Inst), |
| 101 | + "va_arg", Inst); |
| 102 | + |
| 103 | + // Update the va_list to point to the next argument. |
| 104 | + // TODO: Add alignment. |
| 105 | + unsigned Offset = DataLayout->getTypeAllocSize(Inst->getType()); |
| 106 | + std::vector<Value*> Indexes; |
| 107 | + Indexes.push_back(ConstantInt::get(I32, Offset)); |
| 108 | + Value *Next = GetElementPtrInst::Create(CurrentPtr, Indexes, |
| 109 | + "arglist_next", Inst); |
| 110 | + new StoreInst(Next, ArgList, Inst); |
| 111 | + |
| 112 | + Inst->replaceAllUsesWith(Result); |
| 113 | + Inst->eraseFromParent(); |
| 114 | +} |
| 115 | + |
| 116 | +static bool ExpandVarArgCall(CallInst *Call) { |
| 117 | + FunctionType *FuncType = cast<FunctionType>( |
| 118 | + Call->getCalledValue()->getType()->getPointerElementType()); |
| 119 | + if (!FuncType->isFunctionVarArg()) |
| 120 | + return false; |
| 121 | + |
| 122 | + LLVMContext *Context = |
| 123 | + &Call->getParent()->getParent()->getParent()->getContext(); |
| 124 | + |
| 125 | + // Split argument list into fixed and variable arguments. |
| 126 | + std::vector<Value*> FixedArgs; |
| 127 | + std::vector<Value*> VarArgs; |
| 128 | + for (unsigned I = 0; I < FuncType->getNumParams(); ++I) |
| 129 | + FixedArgs.push_back(Call->getArgOperand(I)); |
| 130 | + for (unsigned I = FuncType->getNumParams(); |
| 131 | + I < Call->getNumArgOperands(); ++I) |
| 132 | + VarArgs.push_back(Call->getArgOperand(I)); |
| 133 | + |
| 134 | + // Create struct type for packing variable arguments into. |
| 135 | + std::vector<Type*> VarArgsTypes; |
| 136 | + for (std::vector<Value*>::iterator Iter = VarArgs.begin(); |
| 137 | + Iter != VarArgs.end(); |
| 138 | + ++Iter) { |
| 139 | + VarArgsTypes.push_back((*Iter)->getType()); |
| 140 | + } |
| 141 | + // TODO: We create this as packed for now, but we might need to add |
| 142 | + // alignments later. |
| 143 | + StructType *VarArgsTy = StructType::create(VarArgsTypes, "vararg_call", true); |
| 144 | + |
| 145 | + // Allocate space for the variable argument buffer. Do this at the |
| 146 | + // start of the function so that we don't leak space if the function |
| 147 | + // is called in a loop. |
| 148 | + Function *Func = Call->getParent()->getParent(); |
| 149 | + Instruction *Buf = new AllocaInst(VarArgsTy, "vararg_buffer"); |
| 150 | + Func->getEntryBlock().getInstList().push_front(Buf); |
| 151 | + |
| 152 | + // Copy variable arguments into buffer. |
| 153 | + int Index = 0; |
| 154 | + for (std::vector<Value*>::iterator Iter = VarArgs.begin(); |
| 155 | + Iter != VarArgs.end(); |
| 156 | + ++Iter, ++Index) { |
| 157 | + std::vector<Value*> Indexes; |
| 158 | + Indexes.push_back(ConstantInt::get(*Context, APInt(32, 0))); |
| 159 | + Indexes.push_back(ConstantInt::get(*Context, APInt(32, Index))); |
| 160 | + Value *Ptr = GetElementPtrInst::Create(Buf, Indexes, "vararg_ptr", Call); |
| 161 | + new StoreInst(*Iter, Ptr, Call); |
| 162 | + } |
| 163 | + |
| 164 | + // Cast function to new type to add our extra pointer argument. |
| 165 | + std::vector<Type*> ArgTypes(FuncType->param_begin(), FuncType->param_end()); |
| 166 | + ArgTypes.push_back(VarArgsTy->getPointerTo()); |
| 167 | + FunctionType *NFTy = FunctionType::get(FuncType->getReturnType(), |
| 168 | + ArgTypes, false); |
| 169 | + Value *CastFunc = new BitCastInst(Call->getCalledValue(), |
| 170 | + NFTy->getPointerTo(), "vararg_func", Call); |
| 171 | + |
| 172 | + // Create the converted function call. |
| 173 | + FixedArgs.push_back(Buf); |
| 174 | + Value *NewCall = CallInst::Create(CastFunc, FixedArgs, "", Call); |
| 175 | + NewCall->takeName(Call); |
| 176 | + Call->replaceAllUsesWith(NewCall); |
| 177 | + Call->eraseFromParent(); |
| 178 | + |
| 179 | + return true; |
| 180 | +} |
| 181 | + |
| 182 | +bool ExpandVarArgs::runOnModule(Module &M) { |
| 183 | + bool Changed = false; |
| 184 | + TargetData DataLayout(&M); |
| 185 | + |
| 186 | + for (Module::iterator Iter = M.begin(), E = M.end(); Iter != E; ) { |
| 187 | + Function *Func = Iter++; |
| 188 | + |
| 189 | + for (Function::iterator BB = Func->begin(), E = Func->end(); |
| 190 | + BB != E; |
| 191 | + ++BB) { |
| 192 | + for (BasicBlock::iterator Iter = BB->begin(), E = BB->end(); |
| 193 | + Iter != E; ) { |
| 194 | + Instruction *Inst = Iter++; |
| 195 | + if (VAArgInst *VI = dyn_cast<VAArgInst>(Inst)) { |
| 196 | + Changed = true; |
| 197 | + ExpandVAArgInst(VI, &DataLayout); |
| 198 | + } else if (CallInst *Call = dyn_cast<CallInst>(Inst)) { |
| 199 | + Changed |= ExpandVarArgCall(Call); |
| 200 | + } |
| 201 | + } |
| 202 | + } |
| 203 | + |
| 204 | + if (Func->isVarArg()) { |
| 205 | + Changed = true; |
| 206 | + ExpandVarArgFunc(Func); |
| 207 | + } |
| 208 | + } |
| 209 | + |
| 210 | + return Changed; |
| 211 | +} |
| 212 | + |
| 213 | +ModulePass *createExpandVarArgsPass() { |
| 214 | + return new ExpandVarArgs(); |
| 215 | +} |
0 commit comments