blob: 410d5d0ef855814b97ed2aeb70cc3a6e712f3b9b [file] [log] [blame]
//===--------- ABI.h - Processor ABI customization hooks --------*- C++ -*-===//
//
// Copyright (C) 2005 to 2013 Chris Lattner, Duncan Sands et al.
//
// This file is part of DragonEgg.
//
// DragonEgg 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.
//
// DragonEgg 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
// DragonEgg; see the file COPYING. If not, write to the Free Software
// Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
//
//===----------------------------------------------------------------------===//
// This file 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 DRAGONEGG_ABI_H
#define DRAGONEGG_ABI_H
// Plugin headers
#include "dragonegg/Internals.h"
#include "dragonegg/Target.h"
#include "dragonegg/TypeConversion.h"
// LLVM headers
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LLVMContext.h"
namespace llvm { class BasicBlock; }
/// DefaultABIClient - This is a simple implementation of the ABI client
/// interface that can be subclassed.
struct DefaultABIClient {
virtual void anchor();
virtual ~DefaultABIClient() {}
virtual llvm::CallingConv::ID getCallingConv(void) = 0;
virtual bool isShadowReturn() const { return false; }
/// HandleScalarResult - This callback is invoked if the function returns a
/// simple scalar result value, which is of type RetTy.
virtual void HandleScalarResult(llvm::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. The bit conversion should start at byte Offset
/// within the struct, and ScalarTy is not necessarily big enough to cover
/// the entire struct.
virtual void HandleAggregateResultAsScalar(llvm::Type */*ScalarTy*/,
unsigned /*Offset*/ = 0) {}
/// HandleAggregateResultAsAggregate - This callback is invoked if the function
/// returns an aggregate value using multiple return values.
virtual void HandleAggregateResultAsAggregate(llvm::Type */*AggrTy*/) {}
/// HandleAggregateShadowResult - This callback is invoked if the function
/// returns an aggregate value by using a "shadow" first parameter, which is
/// a pointer to the aggregate, of type PtrArgTy. If RetPtr is set to true,
/// the pointer argument itself is returned from the function.
virtual void HandleAggregateShadowResult(llvm::PointerType */*PtrArgTy*/,
bool /*RetPtr*/) {}
/// HandleScalarShadowResult - This callback is invoked if the function
/// returns a scalar value by using a "shadow" first parameter, which is a
/// pointer to the scalar, of type PtrArgTy. If RetPtr is set to true,
/// the pointer argument itself is returned from the function.
virtual void HandleScalarShadowResult(llvm::PointerType */*PtrArgTy*/,
bool /*RetPtr*/) {}
/// HandleScalarArgument - This is the primary callback that specifies an
/// LLVM argument to pass. It is only used for first class types.
/// If RealSize is non Zero then it specifies number of bytes to access
/// from LLVMTy.
virtual void HandleScalarArgument(llvm::Type */*LLVMTy*/, tree_node */*type*/,
unsigned /*RealSize*/ = 0) {}
/// HandleByInvisibleReferenceArgument - This callback is invoked if a pointer
/// (of type PtrTy) to the argument is passed rather than the argument itself.
virtual void HandleByInvisibleReferenceArgument(llvm::Type */*PtrTy*/,
tree_node */*type*/) {}
/// HandleByValArgument - This callback is invoked if the aggregate function
/// argument is passed by value.
virtual void HandleByValArgument(llvm::Type */*LLVMTy*/,
tree_node */*type*/) {}
/// HandleFCAArgument - This callback is invoked if the aggregate function
/// argument is passed by value as a first class aggregate.
virtual void HandleFCAArgument(llvm::Type */*LLVMTy*/, tree_node */*type*/) {}
/// 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.
virtual void EnterField(unsigned /*FieldNo*/, llvm::Type */*StructTy*/) {}
virtual void ExitField() {}
virtual void HandlePad(llvm::Type */*LLVMTy*/) {}
};
// LLVM_SHOULD_NOT_RETURN_COMPLEX_IN_MEMORY - A hook to allow
// special _Complex handling. Return true if X should be returned using
// multiple value return instruction.
#ifndef LLVM_SHOULD_NOT_RETURN_COMPLEX_IN_MEMORY
#define LLVM_SHOULD_NOT_RETURN_COMPLEX_IN_MEMORY(X) false
#endif
// LLVM_SHOULD_NOT_USE_SHADOW_RETURN - A hook to allow aggregates to be
// returned in registers.
#ifndef LLVM_SHOULD_NOT_USE_SHADOW_RETURN
#define LLVM_SHOULD_NOT_USE_SHADOW_RETURN(X, CC) false
#endif
// doNotUseShadowReturn - Return true if the specified GCC type
// should not be returned using a pointer to struct parameter.
extern bool doNotUseShadowReturn(tree_node *type, tree_node *fndecl,
llvm::CallingConv::ID CC);
/// isSingleElementStructOrArray - If this is (recursively) a structure with one
/// field or an array with one element, return the field type, otherwise return
/// null. Returns null for complex number types. If ignoreZeroLength, the
/// struct (recursively) may include zero-length fields in addition to the
/// single element that has data. If rejectFatBitField, and the single element
/// is a bitfield of a type that's bigger than the struct, return null anyway.
extern tree_node *isSingleElementStructOrArray(
tree_node *type, bool ignoreZeroLength, bool rejectFatBitfield);
/// isZeroSizedStructOrUnion - Returns true if this is a struct or union
/// which is zero bits wide.
extern bool isZeroSizedStructOrUnion(tree_node *type);
// getLLVMScalarTypeForStructReturn - Return LLVM Type if TY can be
// returned as a scalar, otherwise return NULL. This is the default
// target independent implementation.
inline llvm::Type *
getLLVMScalarTypeForStructReturn(tree_node *type, unsigned *Offset) {
llvm::Type *Ty = ConvertType(type);
uint64_t Size = getDataLayout().getTypeAllocSize(Ty);
*Offset = 0;
if (Size == 0)
return llvm::Type::getVoidTy(llvm::getGlobalContext());
else if (Size == 1)
return llvm::Type::getInt8Ty(llvm::getGlobalContext());
else if (Size == 2)
return llvm::Type::getInt16Ty(llvm::getGlobalContext());
else if (Size <= 4)
return llvm::Type::getInt32Ty(llvm::getGlobalContext());
else if (Size <= 8)
return llvm::Type::getInt64Ty(llvm::getGlobalContext());
else if (Size <= 16)
return llvm::IntegerType::get(llvm::getGlobalContext(), 128);
else if (Size <= 32)
return llvm::IntegerType::get(llvm::getGlobalContext(), 256);
return NULL;
}
// getLLVMAggregateTypeForStructReturn - Return LLVM type if TY can be
// returns as multiple values, otherwise return NULL. This is the default
// target independent implementation.
inline llvm::Type *getLLVMAggregateTypeForStructReturn(tree_node */*type*/) {
return NULL;
}
#ifndef LLVM_TRY_PASS_AGGREGATE_CUSTOM
#define LLVM_TRY_PASS_AGGREGATE_CUSTOM(T, E, CC, C) false
#endif
// LLVM_SHOULD_PASS_VECTOR_IN_INTEGER_REGS - Return true if this vector
// type should be passed as integer registers. Generally vectors which are
// not part of the target architecture should do this.
#ifndef LLVM_SHOULD_PASS_VECTOR_IN_INTEGER_REGS
#define LLVM_SHOULD_PASS_VECTOR_IN_INTEGER_REGS(TY) false
#endif
// LLVM_SHOULD_PASS_VECTOR_USING_BYVAL_ATTR - Return true if this vector
// type should be passed byval. Used for generic vectors on x86-64.
#ifndef LLVM_SHOULD_PASS_VECTOR_USING_BYVAL_ATTR
#define LLVM_SHOULD_PASS_VECTOR_USING_BYVAL_ATTR(X) false
#endif
// LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR - Return true if this aggregate
// value should be passed by value, i.e. passing its address with the byval
// attribute bit set. The default is false.
#ifndef LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR
#define LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(X, TY) false
#endif
// LLVM_SHOULD_PASS_AGGREGATE_AS_FCA - Return true if this aggregate value
// should be passed by value as a first class aggregate. The default is false.
#ifndef LLVM_SHOULD_PASS_AGGREGATE_AS_FCA
#define LLVM_SHOULD_PASS_AGGREGATE_AS_FCA(X, TY) false
#endif
// LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS - Return true if this aggregate
// value should be passed in a mixture of integer, floating point, and vector
// registers. The routine should also return by reference a vector of the
// types of the registers being used. The default is false.
#ifndef LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS
#define LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(T, TY, CC, E) false
#endif
// LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS - Only called if
// LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS returns true. This returns true if
// there are only enough unused argument passing registers to pass a part of
// the aggregate. Note, this routine should return false if none of the needed
// registers are available.
#ifndef LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS
#define LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(E, SE, ISR, CC) false
#endif
// LLVM_BYVAL_ALIGNMENT - Returns the alignment of the type in bytes, if known,
// in the getGlobalContext() of its use as a function parameter.
// Note that the alignment in the TYPE node is usually the alignment appropriate
// when the type is used within a struct, which may or may not be appropriate
// here.
#ifndef LLVM_BYVAL_ALIGNMENT
#define LLVM_BYVAL_ALIGNMENT(T) 0
#endif
// 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). We also do it for single-element structs when the
// single element is a bitfield of a type bigger than the struct; the code
// for field-by-field struct passing does not handle this one right.
#ifndef LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS
#define LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS(X, Y, Z) \
!isSingleElementStructOrArray((X), false, true)
#endif
// LLVM_SHOULD_RETURN_SELT_STRUCT_AS_SCALAR - Return a TYPE tree if this single
// element struct should be returned using the convention for that scalar TYPE,
// 0 otherwise.
// The returned TYPE must be the same size as X for this to work; that is
// checked elsewhere. (Structs where this is not the case can be constructed
// by abusing the __aligned__ attribute.)
#ifndef LLVM_SHOULD_RETURN_SELT_STRUCT_AS_SCALAR
#define LLVM_SHOULD_RETURN_SELT_STRUCT_AS_SCALAR(X) \
isSingleElementStructOrArray(X, false, false)
#endif
// LLVM_SHOULD_RETURN_VECTOR_AS_SCALAR - Return a TYPE tree if this vector type
// should be returned using the convention for that scalar TYPE, 0 otherwise.
// X may be evaluated more than once.
#ifndef LLVM_SHOULD_RETURN_VECTOR_AS_SCALAR
#define LLVM_SHOULD_RETURN_VECTOR_AS_SCALAR(X, Y) 0
#endif
// LLVM_SHOULD_RETURN_VECTOR_AS_SHADOW - Return true if this vector type
// should be returned using the aggregate shadow (sret) convention, 0 otherwise.
// X may be evaluated more than once.
#ifndef LLVM_SHOULD_RETURN_VECTOR_AS_SHADOW
#define LLVM_SHOULD_RETURN_VECTOR_AS_SHADOW(X, Y) 0
#endif
// LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN - Return LLVM Type if X can be
// returned as a scalar, otherwise return NULL.
#ifndef LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN
#define LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN(X, Y) \
getLLVMScalarTypeForStructReturn((X), (Y))
#endif
// LLVM_AGGR_TYPE_FOR_STRUCT_RETURN - Return LLVM Type if X can be
// returned as an aggregate, otherwise return NULL.
#ifndef LLVM_AGGR_TYPE_FOR_STRUCT_RETURN
#define LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(X, CC) \
getLLVMAggregateTypeForStructReturn(X)
#endif
// LLVM_EXTRACT_MULTIPLE_RETURN_VALUE - Extract multiple return value from
// SRC and assign it to DEST. Each target that supports multiple return
// value must implement this hook.
#ifndef LLVM_EXTRACT_MULTIPLE_RETURN_VALUE
#define LLVM_EXTRACT_MULTIPLE_RETURN_VALUE(Src, Dest, V, B) \
llvm_default_extract_multiple_return_value((Src), (Dest), (V), (B))
#endif
inline void llvm_default_extract_multiple_return_value(
llvm::Value */*Src*/, llvm::Value */*Dest*/, bool /*isVolatile*/,
LLVMBuilder &/*Builder*/) {
llvm_unreachable("LLVM_EXTRACT_MULTIPLE_RETURN_VALUE is not implemented!");
}
/// 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.
///
class DefaultABI {
protected:
DefaultABIClient &C;
public:
DefaultABI(DefaultABIClient &c);
bool isShadowReturn() const;
/// 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_node *type, tree_node *fn, bool isBuiltin);
/// 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_node *type, std::vector<llvm::Type *> &ScalarElts,
llvm::AttrBuilder *AttrBuilder = NULL);
/// HandleUnion - Handle a UNION_TYPE or QUAL_UNION_TYPE tree.
///
void HandleUnion(tree_node *type, std::vector<llvm::Type *> &ScalarElts);
/// 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. If Size is set we pass only that many bytes.
void PassInIntegerRegisters(tree_node *type,
std::vector<llvm::Type *> &ScalarElts,
unsigned origSize, bool DontCheckAlignment);
/// PassInMixedRegisters - Given an aggregate value that should be passed in
/// mixed integer, floating point, and vector registers, convert it to a
/// structure containing the specified struct elements in.
void PassInMixedRegisters(llvm::Type *Ty, std::vector<llvm::Type *> &OrigElts,
std::vector<llvm::Type *> &ScalarElts);
};
#endif /* DRAGONEGG_ABI_H */