1 /* 2 * Copyright 2012, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <llvm/ADT/Triple.h> 18 #include <llvm/DerivedTypes.h> 19 #include <llvm/Function.h> 20 #include <llvm/Instructions.h> 21 #include <llvm/IRBuilder.h> 22 #include <llvm/Module.h> 23 #include <llvm/Pass.h> 24 #include <llvm/Type.h> 25 #include <llvm/Target/TargetData.h> 26 27 #include "bcc/AndroidBitcode/ABCExpandVAArgPass.h" 28 29 #include "Mips/MipsABCCompilerDriver.h" 30 31 namespace { 32 33 class MipsABCExpandVAArg : public bcc::ABCExpandVAArgPass { 34 public: 35 virtual const char *getPassName() const { 36 return "Mips LLVM va_arg Instruction Expansion Pass"; 37 } 38 39 private: 40 // Derivative work from external/clang/lib/CodeGen/TargetInfo.cpp. 41 virtual llvm::Value *expandVAArg(llvm::Instruction *pInst) { 42 llvm::Type *pty = pInst->getType(); 43 llvm::Type *ty = pty->getContainedType(0); 44 llvm::Value *va_list_addr = pInst->getOperand(0); 45 llvm::IRBuilder<> builder(pInst); 46 const llvm::TargetData *td = getAnalysisIfAvailable<llvm::TargetData>(); 47 48 llvm::Type *bp = llvm::Type::getInt8PtrTy(*mContext); 49 llvm::Type *bpp = bp->getPointerTo(0); 50 llvm::Value *va_list_addr_bpp = builder.CreateBitCast(va_list_addr, 51 bpp, "ap"); 52 llvm::Value *addr = builder.CreateLoad(va_list_addr_bpp, "ap.cur"); 53 int64_t type_align = td->getABITypeAlignment(ty); 54 llvm::Value *addr_typed; 55 llvm::IntegerType *int_ty = llvm::Type::getInt32Ty(*mContext); 56 57 if (type_align > 4) { 58 llvm::Value *addr_as_int = builder.CreatePtrToInt(addr, int_ty); 59 llvm::Value *inc = llvm::ConstantInt::get(int_ty, type_align - 1); 60 llvm::Value *mask = llvm::ConstantInt::get(int_ty, -type_align); 61 llvm::Value *add_v = builder.CreateAdd(addr_as_int, inc); 62 llvm::Value *and_v = builder.CreateAnd(add_v, mask); 63 addr_typed = builder.CreateIntToPtr(and_v, pty); 64 } 65 else { 66 addr_typed = builder.CreateBitCast(addr, pty); 67 } 68 69 llvm::Value *aligned_addr = builder.CreateBitCast(addr_typed, bp); 70 type_align = std::max((unsigned)type_align, (unsigned) 4); 71 uint64_t offset = 72 llvm::RoundUpToAlignment(td->getTypeSizeInBits(ty) / 8, type_align); 73 llvm::Value *next_addr = 74 builder.CreateGEP(aligned_addr, llvm::ConstantInt::get(int_ty, offset), 75 "ap.next"); 76 builder.CreateStore(next_addr, va_list_addr_bpp); 77 78 return addr_typed; 79 } 80 81 }; 82 83 } // end anonymous namespace 84 85 namespace bcc { 86 87 ABCExpandVAArgPass *MipsABCCompilerDriver::createExpandVAArgPass() const { 88 return new MipsABCExpandVAArg(); 89 } 90 91 } // end namespace bcc 92