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