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