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 "Mips/MipsABCCompilerDriver.h"
3042b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
3142b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liaonamespace {
3242b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
3342b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liaoclass MipsABCExpandVAArg : public bcc::ABCExpandVAArgPass {
3442b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liaopublic:
3542b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao  virtual const char *getPassName() const {
3642b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    return "Mips 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  virtual 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    llvm::Value *va_list_addr_bpp = builder.CreateBitCast(va_list_addr,
5142b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao                                                          bpp, "ap");
5242b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    llvm::Value *addr = builder.CreateLoad(va_list_addr_bpp, "ap.cur");
5342b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    int64_t type_align = td->getABITypeAlignment(ty);
5442b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    llvm::Value *addr_typed;
5542b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    llvm::IntegerType *int_ty = llvm::Type::getInt32Ty(*mContext);
5642b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
5742b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    if (type_align > 4) {
5842b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      llvm::Value *addr_as_int = builder.CreatePtrToInt(addr, int_ty);
5942b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      llvm::Value *inc = llvm::ConstantInt::get(int_ty, type_align - 1);
6042b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      llvm::Value *mask = llvm::ConstantInt::get(int_ty, -type_align);
6142b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      llvm::Value *add_v = builder.CreateAdd(addr_as_int, inc);
6242b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      llvm::Value *and_v = builder.CreateAnd(add_v, mask);
6342b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      addr_typed = builder.CreateIntToPtr(and_v, pty);
6442b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    }
6542b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    else {
6642b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      addr_typed = builder.CreateBitCast(addr, pty);
6742b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    }
6842b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
6942b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    llvm::Value *aligned_addr = builder.CreateBitCast(addr_typed, bp);
7042b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    type_align = std::max((unsigned)type_align, (unsigned) 4);
7142b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    uint64_t offset =
7242b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      llvm::RoundUpToAlignment(td->getTypeSizeInBits(ty) / 8, type_align);
7342b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    llvm::Value *next_addr =
7442b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao      builder.CreateGEP(aligned_addr, llvm::ConstantInt::get(int_ty, offset),
7542b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao                        "ap.next");
7642b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    builder.CreateStore(next_addr, va_list_addr_bpp);
7742b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
7842b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao    return addr_typed;
7942b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao  }
8042b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
8142b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao};
8242b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
8342b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao} // end anonymous namespace
8442b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
8542b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liaonamespace bcc {
8642b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
8742b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei LiaoABCExpandVAArgPass *MipsABCCompilerDriver::createExpandVAArgPass() const {
8842b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao  return new MipsABCExpandVAArg();
8942b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao}
9042b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao
9142b88c3b3cdadf6fcd367ee2bc620c0c94bbfe1bShih-wei Liao} // end namespace bcc
92