142b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao/*
242b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao * Copyright 2012, The Android Open Source Project
342b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao *
442b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao * Licensed under the Apache License, Version 2.0 (the "License");
542b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao * you may not use this file except in compliance with the License.
642b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao * You may obtain a copy of the License at
742b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao *
842b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao *     http://www.apache.org/licenses/LICENSE-2.0
942b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao *
1042b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao * Unless required by applicable law or agreed to in writing, software
1142b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao * distributed under the License is distributed on an "AS IS" BASIS,
1242b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1342b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao * See the License for the specific language governing permissions and
1442b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao * limitations under the License.
1542b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao */
1642b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
1742b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao#include <llvm/ADT/Triple.h>
1842b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao#include <llvm/DerivedTypes.h>
1942b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao#include <llvm/Function.h>
2042b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao#include <llvm/Instructions.h>
2142b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao#include <llvm/IRBuilder.h>
2242b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao#include <llvm/Module.h>
2342b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao#include <llvm/Pass.h>
2442b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao#include <llvm/Type.h>
2542b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao#include <llvm/Target/TargetData.h>
2642b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
2742b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao#include "bcc/AndroidBitcode/ABCExpandVAArgPass.h"
2842b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
2942b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao#include "ARM/ARMABCCompilerDriver.h"
3042b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
3142b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liaonamespace {
3242b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
3342b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liaoclass ARMABCExpandVAArg : public bcc::ABCExpandVAArgPass {
3442b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liaopublic:
3542b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao  virtual const char *getPassName() const {
3642b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    return "ARM LLVM va_arg Instruction Expansion Pass";
3742b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao  }
3842b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
3942b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liaoprivate:
4042b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao  // Derivative work from external/clang/lib/CodeGen/TargetInfo.cpp.
4142b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao  llvm::Value *expandVAArg(llvm::Instruction *pInst) {
4242b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    llvm::Type *pty = pInst->getType();
4342b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    llvm::Type *ty = pty->getContainedType(0);
4442b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    llvm::Value *va_list_addr = pInst->getOperand(0);
4542b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    llvm::IRBuilder<> builder(pInst);
4642b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    const llvm::TargetData *td = getAnalysisIfAvailable<llvm::TargetData>();
4742b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
4842b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    llvm::Type *bp = llvm::Type::getInt8PtrTy(*mContext);
4942b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    llvm::Type *bpp = bp->getPointerTo(0);
5042b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
5142b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    llvm::Value *va_list_addr_bpp =
5242b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao        builder.CreateBitCast(va_list_addr, bpp, "ap");
5342b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    llvm::Value *addr = builder.CreateLoad(va_list_addr_bpp, "ap.cur");
5442b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    // Handle address alignment for type alignment > 32 bits.
5542b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    uint64_t ty_align = td->getABITypeAlignment(ty);
5642b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
5742b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    if (ty_align > 4) {
5842b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      assert((ty_align & (ty_align - 1)) == 0 &&
5942b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao        "Alignment is not power of 2!");
6042b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      llvm::Value *addr_as_int =
6142b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao        builder.CreatePtrToInt(addr, llvm::Type::getInt32Ty(*mContext));
6242b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      addr_as_int = builder.CreateAdd(addr_as_int,
6342b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao        builder.getInt32(ty_align-1));
6442b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      addr_as_int = builder.CreateAnd(addr_as_int,
6542b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao        builder.getInt32(~(ty_align-1)));
6642b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      addr = builder.CreateIntToPtr(addr_as_int, bp);
6742b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    }
6842b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    llvm::Value *addr_typed = builder.CreateBitCast(addr, pty);
6942b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
7042b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    uint64_t offset = llvm::RoundUpToAlignment(td->getTypeSizeInBits(ty)/8, 4);
7142b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    llvm::Value *next_addr = builder.CreateGEP(addr,
7242b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      llvm::ConstantInt::get(llvm::Type::getInt32Ty(*mContext), offset),
7342b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      "ap.next");
7442b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    builder.CreateStore(next_addr, va_list_addr_bpp);
7542b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    return addr_typed;
7642b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao  }
7742b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
7842b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao};
7942b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
8042b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao} // end anonymous namespace
8142b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
8242b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liaonamespace bcc {
8342b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
8442b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei LiaoABCExpandVAArgPass *ARMABCCompilerDriver::createExpandVAArgPass() const {
8542b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao  return new ARMABCExpandVAArg();
8642b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao}
8742b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
8842b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao} // end namespace bcc
89