/* APPLE LOCAL begin LLVM (ENTIRE FILE!)  */
/* Processor ABI customization hooks
Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
Contributed by Chris Lattner (sabre@nondot.org)

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING.  If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.  */

//===----------------------------------------------------------------------===//
// This is a C++ header file that specifies how argument values are passed and
// returned from function calls.  This allows the target to specialize handling
// of things like how structures are passed by-value.
//===----------------------------------------------------------------------===//

#ifndef LLVM_ABI_H
#define LLVM_ABI_H

#include "llvm-internal.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Target/TargetData.h"

namespace llvm {
  class BasicBlock;
}
extern "C" {
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
}  

/// DefaultABIClient - This is a simple implementation of the ABI client
/// interface that can be subclassed.
struct DefaultABIClient {
  bool isStructReturn() { return false; }
  
  /// HandleScalarResult - This callback is invoked if the function returns a
  /// simple scalar result value.
  void HandleScalarResult(const Type *RetTy) {}

  /// HandleAggregateResultAsScalar - This callback is invoked if the function
  /// returns an aggregate value by bit converting it to the specified scalar
  /// type and returning that.
  void HandleAggregateResultAsScalar(const Type *ScalarTy) {}
  
  /// HandleAggregateShadowArgument - This callback is invoked if the function
  /// returns an aggregate value by using a "shadow" first parameter.  If RetPtr
  /// is set to true, the pointer argument itself is returned from the function.
  void HandleAggregateShadowArgument(const PointerType *PtrArgTy, bool RetPtr){}
  
  
  /// HandleScalarArgument - This is the primary callback that specifies an LLVM
  /// argument to pass.
  void HandleScalarArgument(const llvm::Type *LLVMTy, tree argTreeType) {}
  
  /// EnterField - Called when we're about the enter the field of a struct
  /// or union.  FieldNo is the number of the element we are entering in the
  /// LLVM Struct, StructTy is the LLVM type of the struct we are entering.
  void EnterField(unsigned FieldNo, const llvm::Type *StructTy) {}
  void ExitField() {}
};

/// isAggregateTreeType - Return true if the specified GCC type is an aggregate
/// that cannot live in an LLVM register.
static bool isAggregateTreeType(tree type) {
  return TREE_CODE(type) == RECORD_TYPE || TREE_CODE(type) == ARRAY_TYPE ||
         TREE_CODE(type) == UNION_TYPE  || TREE_CODE(type) == COMPLEX_TYPE;
}

/// isSingleElementStructOrArray - If this is (recursively) a structure with one
/// field or an array with one element, return the field type, otherwise return
/// null.
static tree isSingleElementStructOrArray(tree type) {
  // Scalars are good.
  if (!isAggregateTreeType(type)) return type;
  
  tree FoundField = 0;
  switch (TREE_CODE(type)) {
  case UNION_TYPE:     // Single element unions don't count.
  case COMPLEX_TYPE:   // Complex values are like 2-element records.
  default:
    return 0;
  case RECORD_TYPE:
    // If this record has variable length, reject it.
    if (TREE_CODE(TYPE_SIZE(type)) != INTEGER_CST)
      return 0;

    for (tree Field = TYPE_FIELDS(type); Field; Field = TREE_CHAIN(Field))
      if (TREE_CODE(Field) == FIELD_DECL) {
        if (!FoundField)
          FoundField = TREE_TYPE(Field);
        else
          return 0;   // More than one field.
      }
    return FoundField ? isSingleElementStructOrArray(FoundField) : 0;
  case ARRAY_TYPE:
    if (!isArrayCompatible(type))
      return 0;
    tree length = arrayLength(type);
    if (!length || !integer_onep(length))
      return 0;
    return isSingleElementStructOrArray(TREE_TYPE(type));
  }
}

// LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS - Return true if this aggregate
// value should be passed in integer registers.  By default, we do this for all
// values that are not single-element structs.  This ensures that things like
// {short,short} are passed in one 32-bit chunk, not as two arguments (which
// would often be 64-bits).
#ifndef LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS
#define LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS(X) \
   !isSingleElementStructOrArray(type)
#endif

/// DefaultABI - This class implements the default LLVM ABI where structures are
/// passed by decimating them into individual components and unions are passed
/// by passing the largest member of the union.
///
template<typename Client>
class DefaultABI {
protected:
  Client &C;
public:
  DefaultABI(Client &c) : C(c) {}

  bool isStructReturn() const { return C.isStructReturn(); }
  
  /// HandleReturnType - This is invoked by the target-independent code for the
  /// return type. It potentially breaks down the argument and invokes methods
  /// on the client that indicate how its pieces should be handled.  This
  /// handles things like returning structures via hidden parameters.
  void HandleReturnType(tree type) {
    const Type *Ty = ConvertType(type);
    if (Ty->isFirstClassType() || Ty == Type::VoidTy) {
      // Return scalar values normally.
      C.HandleScalarResult(Ty);
    } else if (TYPE_SIZE(type) && TREE_CODE(TYPE_SIZE(type)) == INTEGER_CST &&
               !aggregate_value_p(type, current_function_decl) &&
               // FIXME: this is a hack around returning 'complex double' by-val
               // which returns in r3/r4/r5/r6 on PowerPC.
               TREE_INT_CST_LOW(TYPE_SIZE_UNIT(type)) <= 8) {
      if (tree SingleElt = isSingleElementStructOrArray(type)) {
        C.HandleAggregateResultAsScalar(ConvertType(SingleElt));
      } else {
        // Otherwise return as an integer value large enough to hold the entire
        // aggregate.
        unsigned Size = TREE_INT_CST_LOW(TYPE_SIZE_UNIT(type));
        if (Size == 0)
          C.HandleAggregateResultAsScalar(Type::VoidTy);
        else if (Size == 1)
          C.HandleAggregateResultAsScalar(Type::Int8Ty);
        else if (Size == 2)
          C.HandleAggregateResultAsScalar(Type::Int16Ty);
        else if (Size <= 4)
          C.HandleAggregateResultAsScalar(Type::Int32Ty);
        else if (Size <= 8)
          C.HandleAggregateResultAsScalar(Type::Int64Ty);
        else {
          assert(0 && "Cannot return this aggregate as a scalar!");
          abort();
        }
      }
    } else {
      // If the function is returning a struct or union, we pass the pointer to
      // the struct as the first argument to the function.

      // FIXME: should return the hidden first argument for some targets
      // (e.g. ELF i386).
      C.HandleAggregateShadowArgument(PointerType::get(Ty), false);
    }
  }
  
  /// HandleArgument - This is invoked by the target-independent code for each
  /// argument type passed into the function.  It potentially breaks down the
  /// argument and invokes methods on the client that indicate how its pieces
  /// should be handled.  This handles things like decimating structures into
  /// their fields.
  void HandleArgument(tree type) {
    const Type *Ty = ConvertType(type);

    if (isPassedByInvisibleReference(type)) { // variable size -> by-ref.
      C.HandleScalarArgument(PointerType::get(Ty), type);
    } else if (Ty->isFirstClassType()) {
      C.HandleScalarArgument(Ty, type);
    } else if (LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS(type)) {
      PassInIntegerRegisters(type, Ty);
    } else if (TREE_CODE(type) == RECORD_TYPE) {
      for (tree Field = TYPE_FIELDS(type); Field; Field = TREE_CHAIN(Field))
        if (TREE_CODE(Field) == FIELD_DECL) {
          unsigned FNo = cast<ConstantInt>(DECL_LLVM(Field))->getZExtValue();
          assert(FNo != ~0U && "Case not handled yet!");
          
          C.EnterField(FNo, Ty);
          HandleArgument(TREE_TYPE(Field));
          C.ExitField();
        }
    } else if (TREE_CODE(type) == COMPLEX_TYPE) {
      C.EnterField(0, Ty);
      HandleArgument(TREE_TYPE(type));
      C.ExitField();
      C.EnterField(1, Ty);
      HandleArgument(TREE_TYPE(type));
      C.ExitField();
    } else if (TREE_CODE(type) == UNION_TYPE) {
      HandleUnion(type);
    } else if (TREE_CODE(type) == ARRAY_TYPE) {
      const ArrayType *ATy = cast<ArrayType>(Ty);
      for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {
        C.EnterField(i, Ty);
        HandleArgument(TREE_TYPE(type));
        C.ExitField();
      }
    } else {
      assert(0 && "unknown aggregate type!");
      abort();
    }
  }

  /// HandleUnion - Handle a UNION_TYPE tree.
  ///
  void HandleUnion(tree type) {
    if (TYPE_TRANSPARENT_UNION(type)) {
      tree Field = TYPE_FIELDS(type);
      assert(Field && "Transparent union must have some elements!");
      while (TREE_CODE(Field) != FIELD_DECL) {
        Field = TREE_CHAIN(Field);
        assert(Field && "Transparent union must have some elements!");
      }
      
      HandleArgument(TREE_TYPE(Field));
    } else {
      // Unions pass the largest element.
      unsigned MaxSize = 0;
      tree MaxElt = 0;
      for (tree Field = TYPE_FIELDS(type); Field; Field = TREE_CHAIN(Field)) {
        if (TREE_CODE(Field) == FIELD_DECL) {
          tree SizeTree = TYPE_SIZE(TREE_TYPE(Field));
          unsigned Size = ((unsigned)TREE_INT_CST_LOW(SizeTree)+7)/8;
          if (Size > MaxSize) {
            MaxSize = Size;
            MaxElt = Field;
          }
        }
      }
      
      if (MaxElt)
        HandleArgument(TREE_TYPE(MaxElt));
    }
  }
    
  /// PassInIntegerRegisters - Given an aggregate value that should be passed in
  /// integer registers, convert it to a structure containing ints and pass all
  /// of the struct elements in.
  void PassInIntegerRegisters(tree type, const Type *Ty) {
    unsigned Size = TREE_INT_CST_LOW(TYPE_SIZE(type))/8;

    // FIXME: We should preserve all aggregate value alignment information.
    // Work around to preserve some aggregate value alignment information:
    // don't bitcast aggregate value to Int64 if its alignment is different
    // from Int64 alignment. ARM backend needs this.
    unsigned Align = TYPE_ALIGN(type)/8;
    unsigned Int64Align = getTargetData().getABITypeAlignment(Type::Int64Ty);
    bool UseInt64 = (Align >= Int64Align);

    // FIXME: In cases where we can, we should use the original struct.
    // Consider cases like { int, int } and {int, short} for example!  This will
    // produce far better LLVM code!
    std::vector<const Type*> Elts;

    unsigned ElementSize = UseInt64 ? 8:4;
    unsigned ArraySize = Size / ElementSize;

    const Type *ATy = NULL;
    const Type *ArrayElementType = NULL;
    if (ArraySize) {
      Size = Size % ElementSize;
      ArrayElementType = (UseInt64)?Type::Int64Ty:Type::Int32Ty;
      ATy = ArrayType::get(ArrayElementType, ArraySize);
      Elts.push_back(ATy);
    }

    if (Size >= 4) {
      Elts.push_back(Type::Int32Ty);
      Size -= 4;
    }
    if (Size >= 2) {
      Elts.push_back(Type::Int16Ty);
      Size -= 2;
    }
    if (Size >= 1) {
      Elts.push_back(Type::Int8Ty);
      Size -= 1;
    }
    assert(Size == 0 && "Didn't cover value?");
    const StructType *STy = StructType::get(Elts, false);

    unsigned i = 0;
    if (ArraySize) {
      C.EnterField(0, STy);
      for (unsigned j = 0; j < ArraySize; ++j) {
        C.EnterField(j, ATy);
        C.HandleScalarArgument(ArrayElementType, 0);
        C.ExitField();
      }
      C.ExitField();
      ++i;
    }
    for (unsigned e = Elts.size(); i != e; ++i) {
      C.EnterField(i, STy);
      C.HandleScalarArgument(Elts[i], 0);
      C.ExitField();
    }
  }
};

/// TheLLVMABI - This can be defined by targets if they want total control over
/// ABI decisions.
///
#ifndef TheLLVMABI
#define TheLLVMABI DefaultABI
#endif

#endif
/* APPLE LOCAL end LLVM (ENTIRE FILE!)  */


syntax highlighted by Code2HTML, v. 0.9.1