//===----- CGCall.h - Encapsulate calling convention details ----*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// These classes wrap the information about a call or function
// definition used to handle ABI compliancy.
//
//===----------------------------------------------------------------------===//

#include "CGCall.h"
#include "CodeGenFunction.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/ParameterAttributes.h"
using namespace clang;
using namespace CodeGen;

/***/

static void 
constructParamAttrListInternal(const Decl *TargetDecl,
                               const llvm::SmallVector<QualType, 16> &ArgTypes,
                               ParamAttrListType &PAL) {
  unsigned FuncAttrs = 0;

  if (TargetDecl) {
    if (TargetDecl->getAttr<NoThrowAttr>())
      FuncAttrs |= llvm::ParamAttr::NoUnwind;
    if (TargetDecl->getAttr<NoReturnAttr>())
      FuncAttrs |= llvm::ParamAttr::NoReturn;
  }

  unsigned Index = 1;
  if (CodeGenFunction::hasAggregateLLVMType(ArgTypes[0])) {
    PAL.push_back(llvm::ParamAttrsWithIndex::get(Index, 
                                                 llvm::ParamAttr::StructRet));
    ++Index;
  } else if (ArgTypes[0]->isPromotableIntegerType()) {
    if (ArgTypes[0]->isSignedIntegerType()) {
      FuncAttrs |= llvm::ParamAttr::SExt;
    } else if (ArgTypes[0]->isUnsignedIntegerType()) {
      FuncAttrs |= llvm::ParamAttr::ZExt;
    }
  }
  if (FuncAttrs)
    PAL.push_back(llvm::ParamAttrsWithIndex::get(0, FuncAttrs));
  for (llvm::SmallVector<QualType, 8>::const_iterator i = ArgTypes.begin() + 1,
         e = ArgTypes.end(); i != e; ++i, ++Index) {
    QualType ParamType = *i;
    unsigned ParamAttrs = 0;
    if (ParamType->isRecordType())
      ParamAttrs |= llvm::ParamAttr::ByVal;
    if (ParamType->isPromotableIntegerType()) {
      if (ParamType->isSignedIntegerType()) {
        ParamAttrs |= llvm::ParamAttr::SExt;
      } else if (ParamType->isUnsignedIntegerType()) {
        ParamAttrs |= llvm::ParamAttr::ZExt;
      }
    }
    if (ParamAttrs)
      PAL.push_back(llvm::ParamAttrsWithIndex::get(Index, ParamAttrs));
  }
}

/***/

// FIXME: Use iterator and sidestep silly type array creation.

CGFunctionInfo::CGFunctionInfo(const FunctionDecl *FD)
  : TheDecl(FD) 
{
  const FunctionType *FTy = FD->getType()->getAsFunctionType();
  const FunctionTypeProto *FTP = dyn_cast<FunctionTypeProto>(FTy);
  
  ArgTypes.push_back(FTy->getResultType());
  if (FTP)
    for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
      ArgTypes.push_back(FTP->getArgType(i));
}

CGFunctionInfo::CGFunctionInfo(const ObjCMethodDecl *MD,
                               const ASTContext &Context)
  : TheDecl(MD) 
{
  ArgTypes.push_back(MD->getResultType());
  ArgTypes.push_back(MD->getSelfDecl()->getType());
  ArgTypes.push_back(Context.getObjCSelType());
  for (ObjCMethodDecl::param_const_iterator i = MD->param_begin(),
         e = MD->param_end(); i != e; ++i)
    ArgTypes.push_back((*i)->getType());
}

void CGFunctionInfo::constructParamAttrList(ParamAttrListType &PAL) const {
  constructParamAttrListInternal(TheDecl, ArgTypes, PAL);
}

/***/

CGCallInfo::CGCallInfo(QualType _ResultType, const CallArgList &_Args)
  : ResultType(_ResultType),
    Args(_Args) {
  ArgTypes.push_back(ResultType);
  for (CallArgList::const_iterator i = Args.begin(), e = Args.end(); i!=e; ++i)
    ArgTypes.push_back(i->second);
}

void CGCallInfo::constructParamAttrList(ParamAttrListType &PAL) const {
  // FIXME: Provide TargetDecl so nounwind, noreturn, etc, etc get set.
  constructParamAttrListInternal(0, ArgTypes, PAL);
}
