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/Core/Log.h" 28 #include "lldb/Target/Process.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 llvm::AllocaInst *return_value_alloc = new llvm::AllocaInst( 186 func->getReturnType(), "var_vector_return_alloc", call_inst); 187 // use the new allocation as the new first argument 188 new_call_args.emplace(new_call_args.begin(), 189 llvm::cast<llvm::Value>(return_value_alloc)); 190 llvm::PointerType *new_func_ptr_type = 191 llvm::PointerType::get(new_func_type, 0); 192 // Create the type cast from the old function type to the new one 193 llvm::Constant *new_func_cast = llvm::ConstantExpr::getCast( 194 llvm::Instruction::BitCast, func, new_func_ptr_type); 195 // create an allocation for a new function pointer 196 llvm::AllocaInst *new_func_ptr = 197 new llvm::AllocaInst(new_func_ptr_type, "new_func_ptr", call_inst); 198 // store the new_func_cast to the newly allocated space 199 (void)new llvm::StoreInst(new_func_cast, new_func_ptr, 200 "new_func_ptr_load_cast", call_inst); 201 // load the new function address ready for a jump 202 llvm::LoadInst *new_func_addr_load = 203 new llvm::LoadInst(new_func_ptr, "load_func_pointer", call_inst); 204 // and create a callinstruction from it 205 llvm::CallInst *new_call_inst = llvm::CallInst::Create( 206 new_func_addr_load, new_call_args, "new_func_call", call_inst); 207 new_call_inst->setCallingConv(call_inst->getCallingConv()); 208 new_call_inst->setTailCall(call_inst->isTailCall()); 209 llvm::LoadInst *lldb_save_result_address = 210 new llvm::LoadInst(return_value_alloc, "save_return_val", call_inst); 211 212 // Now remove the old broken call 213 call_inst->replaceAllUsesWith(lldb_save_result_address); 214 call_inst->eraseFromParent(); 215 changed = true; 216 } 217 return changed; 218 } 219 220 bool fixupRSAllocationStructByValCalls(llvm::Module &module) { 221 // On x86_64, calls to functions in the RS runtime that take an 222 // `rs_allocation` type argument 223 // are actually handled as by-ref params by bcc, but appear to be passed by 224 // value by lldb (the callsite all use 225 // `struct byval`). 226 // On x86_64 Linux, struct arguments are transferred in registers if the 227 // struct size is no bigger than 228 // 128bits [ref](http://www.agner.org/optimize/calling_conventions.pdf) 229 // section 7.1 "Passing and returning objects" 230 // otherwise passed on the stack. 231 // an object of type `rs_allocation` is actually 256bits, so should be passed 232 // on the stack. However, code generated 233 // by bcc actually treats formal params of type `rs_allocation` as 234 // `rs_allocation *` so we need to convert the 235 // calling convention to pass by reference, and remove any hint of byval from 236 // formal parameters. 237 bool changed = false; 238 std::set<llvm::CallInst *> rs_callsites; 239 if (!findRSCallSites(module, rs_callsites, isRSAllocationTyCallSite)) 240 return false; 241 242 std::set<llvm::Function *> rs_functions; 243 244 // for all call instructions 245 for (auto call_inst : rs_callsites) { 246 // add the called function to a set so that we can strip its byval 247 // attributes in another pass 248 rs_functions.insert(call_inst->getCalledFunction()); 249 250 // get the function attributes 251 llvm::AttributeSet call_attribs = call_inst->getAttributes(); 252 253 // iterate over the argument attributes 254 for (size_t i = 1; i <= call_attribs.getNumSlots(); ++i) { 255 // if this argument is passed by val 256 if (call_attribs.hasAttribute(i, llvm::Attribute::ByVal)) { 257 // strip away the byval attribute 258 call_inst->removeAttribute(i, llvm::Attribute::ByVal); 259 changed = true; 260 } 261 } 262 } 263 264 llvm::AttributeSet attr_byval = 265 llvm::AttributeSet::get(module.getContext(), 1u, llvm::Attribute::ByVal); 266 267 // for all called function decls 268 for (auto func : rs_functions) { 269 // inspect all of the arguments in the call 270 llvm::SymbolTableList<llvm::Argument> &arg_list = func->getArgumentList(); 271 for (auto &arg : arg_list) { 272 if (arg.hasByValAttr()) { 273 arg.removeAttr(attr_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