1 //===-- RenderScriptx86ABIFixups.cpp ----------------------------*- C++ -*-===// 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 // C Includes 11 // C++ Includes 12 #include <set> 13 14 // Other libraries and framework includes 15 #include "llvm/ADT/StringRef.h" 16 #include "llvm/IR/BasicBlock.h" 17 #include "llvm/IR/CallSite.h" 18 #include "llvm/IR/Constants.h" 19 #include "llvm/IR/Function.h" 20 #include "llvm/IR/Instruction.h" 21 #include "llvm/IR/Instructions.h" 22 #include "llvm/IR/Module.h" 23 #include "llvm/IRReader/IRReader.h" 24 #include "llvm/Pass.h" 25 26 // Project includes 27 #include "lldb/Target/Process.h" 28 #include "lldb/Utility/Log.h" 29 30 using namespace lldb_private; 31 namespace { 32 33 bool isRSAPICall(llvm::Module &module, llvm::CallInst *call_inst) { 34 // TODO get the list of renderscript modules from lldb and check if 35 // this llvm::Module calls into any of them. 36 (void)module; 37 const auto func_name = call_inst->getCalledFunction()->getName(); 38 if (func_name.startswith("llvm") || func_name.startswith("lldb")) 39 return false; 40 41 if (call_inst->getCalledFunction()->isIntrinsic()) 42 return false; 43 44 return true; 45 } 46 47 bool isRSLargeReturnCall(llvm::Module &module, llvm::CallInst *call_inst) { 48 // i686 and x86_64 returns for large vectors in the RenderScript API are not 49 // handled as normal 50 // register pairs, but as a hidden sret type. This is not reflected in the 51 // debug info or mangled 52 // symbol name, and the android ABI for x86 and x86_64, (as well as the 53 // emulators) specifies there is 54 // no AVX, so bcc generates an sret function because we cannot natively return 55 // 256 bit vectors. 56 // This function simply checks whether a function has a > 128bit return type. 57 // It is perhaps an 58 // unreliable heuristic, and relies on bcc not generating AVX code, so if the 59 // android ABI one day 60 // provides for AVX, this function may go out of fashion. 61 (void)module; 62 if (!call_inst || !call_inst->getCalledFunction()) 63 return false; 64 65 return call_inst->getCalledFunction() 66 ->getReturnType() 67 ->getPrimitiveSizeInBits() > 128; 68 } 69 70 bool isRSAllocationPtrTy(const llvm::Type *type) { 71 if (!type->isPointerTy()) 72 return false; 73 auto ptr_type = type->getPointerElementType(); 74 75 return ptr_type->isStructTy() && 76 ptr_type->getStructName().startswith("struct.rs_allocation"); 77 } 78 79 bool isRSAllocationTyCallSite(llvm::Module &module, llvm::CallInst *call_inst) { 80 (void)module; 81 if (!call_inst->hasByValArgument()) 82 return false; 83 for (const auto ¶m : call_inst->operand_values()) 84 if (isRSAllocationPtrTy(param->getType())) 85 return true; 86 return false; 87 } 88 89 llvm::FunctionType *cloneToStructRetFnTy(llvm::CallInst *call_inst) { 90 // on x86 StructReturn functions return a pointer to the return value, rather 91 // than the return 92 // value itself [ref](http://www.agner.org/optimize/calling_conventions.pdf 93 // section 6). 94 // We create a return type by getting the pointer type of the old return type, 95 // and inserting a new 96 // initial argument of pointer type of the original return type. 97 Log *log( 98 GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_EXPRESSIONS)); 99 100 assert(call_inst && "no CallInst"); 101 llvm::Function *orig = call_inst->getCalledFunction(); 102 assert(orig && "CallInst has no called function"); 103 llvm::FunctionType *orig_type = orig->getFunctionType(); 104 auto name = orig->getName(); 105 if (log) 106 log->Printf("%s - cloning to StructRet function for '%s'", __FUNCTION__, 107 name.str().c_str()); 108 109 unsigned num_params = orig_type->getNumParams(); 110 std::vector<llvm::Type *> new_params{num_params + 1, nullptr}; 111 std::vector<llvm::Type *> params{orig_type->param_begin(), 112 orig_type->param_end()}; 113 114 // This may not work if the function is somehow declared void as llvm is 115 // strongly typed 116 // and represents void* with i8* 117 assert(!orig_type->getReturnType()->isVoidTy() && 118 "Cannot add StructRet attribute to void function"); 119 llvm::PointerType *return_type_ptr_type = 120 llvm::PointerType::getUnqual(orig->getReturnType()); 121 assert(return_type_ptr_type && 122 "failed to get function return type PointerType"); 123 if (!return_type_ptr_type) 124 return nullptr; 125 126 if (log) 127 log->Printf("%s - return type pointer type for StructRet clone @ '0x%p':\n", 128 __FUNCTION__, (void *)return_type_ptr_type); 129 // put the the sret pointer argument in place at the beginning of the argument 130 // list. 131 params.emplace(params.begin(), return_type_ptr_type); 132 assert(params.size() == num_params + 1); 133 return llvm::FunctionType::get(return_type_ptr_type, params, 134 orig->isVarArg()); 135 } 136 137 bool findRSCallSites(llvm::Module &module, 138 std::set<llvm::CallInst *> &rs_callsites, 139 bool (*predicate)(llvm::Module &, llvm::CallInst *)) { 140 bool found = false; 141 142 for (auto &func : module.getFunctionList()) 143 for (auto &block : func.getBasicBlockList()) 144 for (auto &inst : block) { 145 llvm::CallInst *call_inst = 146 llvm::dyn_cast_or_null<llvm::CallInst>(&inst); 147 if (!call_inst || !call_inst->getCalledFunction()) 148 // This is not the call-site you are looking for... 149 continue; 150 if (isRSAPICall(module, call_inst) && predicate(module, call_inst)) { 151 rs_callsites.insert(call_inst); 152 found = true; 153 } 154 } 155 return found; 156 } 157 158 bool fixupX86StructRetCalls(llvm::Module &module) { 159 bool changed = false; 160 // changing a basic block while iterating over it seems to have some undefined 161 // behaviour 162 // going on so we find all RS callsites first, then fix them up after 163 // consuming 164 // the iterator. 165 std::set<llvm::CallInst *> rs_callsites; 166 if (!findRSCallSites(module, rs_callsites, isRSLargeReturnCall)) 167 return false; 168 169 for (auto call_inst : rs_callsites) { 170 llvm::FunctionType *new_func_type = cloneToStructRetFnTy(call_inst); 171 assert(new_func_type && 172 "failed to clone functionType for Renderscript ABI fixup"); 173 174 llvm::CallSite call_site(call_inst); 175 llvm::Function *func = call_inst->getCalledFunction(); 176 assert(func && "cannot resolve function in RenderScriptRuntime"); 177 // Copy the original call arguments 178 std::vector<llvm::Value *> new_call_args(call_site.arg_begin(), 179 call_site.arg_end()); 180 181 // Allocate enough space to store the return value of the original function 182 // we pass a pointer to this allocation as the StructRet param, and then 183 // copy its 184 // value into the lldb return value 185 const llvm::DataLayout &DL = module.getDataLayout(); 186 llvm::AllocaInst *return_value_alloc = new llvm::AllocaInst( 187 func->getReturnType(), DL.getAllocaAddrSpace(), "var_vector_return_alloc", 188 call_inst); 189 // use the new allocation as the new first argument 190 new_call_args.emplace(new_call_args.begin(), 191 llvm::cast<llvm::Value>(return_value_alloc)); 192 llvm::PointerType *new_func_ptr_type = 193 llvm::PointerType::get(new_func_type, 0); 194 // Create the type cast from the old function type to the new one 195 llvm::Constant *new_func_cast = llvm::ConstantExpr::getCast( 196 llvm::Instruction::BitCast, func, new_func_ptr_type); 197 // create an allocation for a new function pointer 198 llvm::AllocaInst *new_func_ptr = 199 new llvm::AllocaInst(new_func_ptr_type, DL.getAllocaAddrSpace(), 200 "new_func_ptr", call_inst); 201 // store the new_func_cast to the newly allocated space 202 (new llvm::StoreInst(new_func_cast, new_func_ptr, call_inst)) 203 ->setName("new_func_ptr_load_cast"); 204 // load the new function address ready for a jump 205 llvm::LoadInst *new_func_addr_load = 206 new llvm::LoadInst(new_func_ptr, "load_func_pointer", call_inst); 207 // and create a callinstruction from it 208 llvm::CallInst *new_call_inst = llvm::CallInst::Create( 209 new_func_addr_load, new_call_args, "new_func_call", call_inst); 210 new_call_inst->setCallingConv(call_inst->getCallingConv()); 211 new_call_inst->setTailCall(call_inst->isTailCall()); 212 llvm::LoadInst *lldb_save_result_address = 213 new llvm::LoadInst(return_value_alloc, "save_return_val", call_inst); 214 215 // Now remove the old broken call 216 call_inst->replaceAllUsesWith(lldb_save_result_address); 217 call_inst->eraseFromParent(); 218 changed = true; 219 } 220 return changed; 221 } 222 223 bool fixupRSAllocationStructByValCalls(llvm::Module &module) { 224 // On x86_64, calls to functions in the RS runtime that take an 225 // `rs_allocation` type argument 226 // are actually handled as by-ref params by bcc, but appear to be passed by 227 // value by lldb (the callsite all use 228 // `struct byval`). 229 // On x86_64 Linux, struct arguments are transferred in registers if the 230 // struct size is no bigger than 231 // 128bits [ref](http://www.agner.org/optimize/calling_conventions.pdf) 232 // section 7.1 "Passing and returning objects" 233 // otherwise passed on the stack. 234 // an object of type `rs_allocation` is actually 256bits, so should be passed 235 // on the stack. However, code generated 236 // by bcc actually treats formal params of type `rs_allocation` as 237 // `rs_allocation *` so we need to convert the 238 // calling convention to pass by reference, and remove any hint of byval from 239 // formal parameters. 240 bool changed = false; 241 std::set<llvm::CallInst *> rs_callsites; 242 if (!findRSCallSites(module, rs_callsites, isRSAllocationTyCallSite)) 243 return false; 244 245 std::set<llvm::Function *> rs_functions; 246 247 // for all call instructions 248 for (auto call_inst : rs_callsites) { 249 // add the called function to a set so that we can strip its byval 250 // attributes in another pass 251 rs_functions.insert(call_inst->getCalledFunction()); 252 253 // get the function attributes 254 llvm::AttributeList call_attribs = call_inst->getAttributes(); 255 256 // iterate over the argument attributes 257 for (unsigned I = call_attribs.index_begin(); I != call_attribs.index_end(); 258 I++) { 259 // if this argument is passed by val 260 if (call_attribs.hasAttribute(I, llvm::Attribute::ByVal)) { 261 // strip away the byval attribute 262 call_inst->removeAttribute(I, llvm::Attribute::ByVal); 263 changed = true; 264 } 265 } 266 } 267 268 // for all called function decls 269 for (auto func : rs_functions) { 270 // inspect all of the arguments in the call 271 for (auto &arg : func->args()) { 272 if (arg.hasByValAttr()) { 273 arg.removeAttr(llvm::Attribute::ByVal); 274 changed = true; 275 } 276 } 277 } 278 return changed; 279 } 280 } // end anonymous namespace 281 282 namespace lldb_private { 283 namespace lldb_renderscript { 284 285 bool fixupX86FunctionCalls(llvm::Module &module) { 286 return fixupX86StructRetCalls(module); 287 } 288 289 bool fixupX86_64FunctionCalls(llvm::Module &module) { 290 bool changed = false; 291 changed |= fixupX86StructRetCalls(module); 292 changed |= fixupRSAllocationStructByValCalls(module); 293 return changed; 294 } 295 296 } // end namespace lldb_renderscript 297 } // end namespace lldb_private 298