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 "ARM/ARMABCCompilerDriver.h" 30 31namespace { 32 33class ARMABCExpandVAArg : public bcc::ABCExpandVAArgPass { 34public: 35 virtual const char *getPassName() const { 36 return "ARM LLVM va_arg Instruction Expansion Pass"; 37 } 38 39private: 40 // Derivative work from external/clang/lib/CodeGen/TargetInfo.cpp. 41 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 51 llvm::Value *va_list_addr_bpp = 52 builder.CreateBitCast(va_list_addr, bpp, "ap"); 53 llvm::Value *addr = builder.CreateLoad(va_list_addr_bpp, "ap.cur"); 54 // Handle address alignment for type alignment > 32 bits. 55 uint64_t ty_align = td->getABITypeAlignment(ty); 56 57 if (ty_align > 4) { 58 assert((ty_align & (ty_align - 1)) == 0 && 59 "Alignment is not power of 2!"); 60 llvm::Value *addr_as_int = 61 builder.CreatePtrToInt(addr, llvm::Type::getInt32Ty(*mContext)); 62 addr_as_int = builder.CreateAdd(addr_as_int, 63 builder.getInt32(ty_align-1)); 64 addr_as_int = builder.CreateAnd(addr_as_int, 65 builder.getInt32(~(ty_align-1))); 66 addr = builder.CreateIntToPtr(addr_as_int, bp); 67 } 68 llvm::Value *addr_typed = builder.CreateBitCast(addr, pty); 69 70 uint64_t offset = llvm::RoundUpToAlignment(td->getTypeSizeInBits(ty)/8, 4); 71 llvm::Value *next_addr = builder.CreateGEP(addr, 72 llvm::ConstantInt::get(llvm::Type::getInt32Ty(*mContext), offset), 73 "ap.next"); 74 builder.CreateStore(next_addr, va_list_addr_bpp); 75 return addr_typed; 76 } 77 78}; 79 80} // end anonymous namespace 81 82namespace bcc { 83 84ABCExpandVAArgPass *ARMABCCompilerDriver::createExpandVAArgPass() const { 85 return new ARMABCExpandVAArg(); 86} 87 88} // end namespace bcc 89