blob: 7dc87c467842f014b76ca49850908429cc52dbe4 [file] [log] [blame]
//===------------ DefaultABI.cpp - Default ABI implementation -------------===//
//
// Copyright (C) 2010 to 2013 Rafael Espindola, 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 implements the default ABI.
//===----------------------------------------------------------------------===//
// Plugin headers
#include "dragonegg/ABI.h"
// System headers
#include <gmp.h>
// GCC headers
#include "auto-host.h"
#ifndef ENABLE_BUILD_WITH_CXX
#include <cstring> // Otherwise included by system.h with C linkage.
extern "C" {
#endif
#include "config.h"
// Stop GCC declaring 'getopt' as it can clash with the system's declaration.
#undef HAVE_DECL_GETOPT
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#ifndef ENABLE_BUILD_WITH_CXX
} // extern "C"
#endif
// Trees header.
#include "dragonegg/Trees.h"
using namespace llvm;
void DefaultABIClient::anchor() {}
// doNotUseShadowReturn - Return true if the specified GCC type
// should not be returned using a pointer to struct parameter.
bool doNotUseShadowReturn(tree type, tree fndecl, CallingConv::ID CC) {
(void) CC; // Not used by all ABI macros.
if (!TYPE_SIZE(type))
return false;
if (!isa<INTEGER_CST>(TYPE_SIZE(type)))
return false;
// LLVM says do not use shadow argument.
if (LLVM_SHOULD_NOT_RETURN_COMPLEX_IN_MEMORY(type) ||
LLVM_SHOULD_NOT_USE_SHADOW_RETURN(type, CC))
return true;
// GCC says use shadow argument.
if (aggregate_value_p(type, fndecl))
return false;
return true;
}
/// 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.
tree isSingleElementStructOrArray(tree type, bool ignoreZeroLength,
bool rejectFatBitfield) {
// Complex numbers have two fields.
if (isa<COMPLEX_TYPE>(type))
return 0;
// All other scalars are good.
if (!isa<AGGREGATE_TYPE>(type))
return type;
tree FoundField = 0;
switch (TREE_CODE(type)) {
case QUAL_UNION_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 (!isa<INTEGER_CST>(TYPE_SIZE(type)))
return 0;
for (tree Field = TYPE_FIELDS(type); Field; Field = TREE_CHAIN(Field))
if (isa<FIELD_DECL>(Field)) {
if (ignoreZeroLength) {
if (DECL_SIZE(Field) && isa<INTEGER_CST>(DECL_SIZE(Field)) &&
TREE_INT_CST_LOW(DECL_SIZE(Field)) == 0)
continue;
}
if (!FoundField) {
if (rejectFatBitfield && isa<INTEGER_CST>(TYPE_SIZE(type)) &&
TREE_INT_CST_LOW(TYPE_SIZE(TREE_TYPE(Field))) >
TREE_INT_CST_LOW(TYPE_SIZE(type)))
return 0;
FoundField = TREE_TYPE(Field);
} else {
return 0; // More than one field.
}
}
return FoundField
? isSingleElementStructOrArray(FoundField, ignoreZeroLength, false)
: 0;
case ARRAY_TYPE:
ArrayType *Ty = dyn_cast<ArrayType>(ConvertType(type));
if (!Ty || Ty->getNumElements() != 1)
return 0;
return isSingleElementStructOrArray(TREE_TYPE(type), false, false);
}
}
/// isZeroSizedStructOrUnion - Returns true if this is a struct or union
/// which is zero bits wide.
bool isZeroSizedStructOrUnion(tree type) {
if (!isa<RECORD_OR_UNION_TYPE>(type))
return false;
return int_size_in_bytes(type) == 0;
}
DefaultABI::DefaultABI(DefaultABIClient &c) : C(c) {}
bool DefaultABI::isShadowReturn() const { return C.isShadowReturn(); }
/// 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 DefaultABI::HandleReturnType(tree type, tree fn, bool isBuiltin) {
(void) isBuiltin; // Not used by all ABI macros.
unsigned Offset = 0;
Type *Ty = ConvertType(type);
if (Ty->isVectorTy()) {
// Vector handling is weird on x86. In particular builtin and
// non-builtin function of the same return types can use different
// calling conventions.
tree ScalarType = LLVM_SHOULD_RETURN_VECTOR_AS_SCALAR(type, isBuiltin);
if (ScalarType)
C.HandleAggregateResultAsScalar(ConvertType(ScalarType));
else if (LLVM_SHOULD_RETURN_VECTOR_AS_SHADOW(type, isBuiltin))
C.HandleScalarShadowResult(Ty->getPointerTo(), false);
else
C.HandleScalarResult(Ty);
} else if (Ty->isSingleValueType() || Ty->isVoidTy()) {
// Return scalar values normally.
C.HandleScalarResult(Ty);
} else if (doNotUseShadowReturn(type, fn, C.getCallingConv())) {
tree SingleElt = LLVM_SHOULD_RETURN_SELT_STRUCT_AS_SCALAR(type);
if (SingleElt && TYPE_SIZE(SingleElt) &&
isa<INTEGER_CST>(TYPE_SIZE(SingleElt)) &&
TREE_INT_CST_LOW(TYPE_SIZE_UNIT(type)) ==
TREE_INT_CST_LOW(TYPE_SIZE_UNIT(SingleElt))) {
C.HandleAggregateResultAsScalar(ConvertType(SingleElt));
} else {
// Otherwise return as an integer value large enough to hold the entire
// aggregate.
if (Type *AggrTy =
LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(type, C.getCallingConv()))
C.HandleAggregateResultAsAggregate(AggrTy);
else if (Type *ScalarTy =
LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN(type, &Offset))
C.HandleAggregateResultAsScalar(ScalarTy, Offset);
else
llvm_unreachable("Unable to determine how to return this aggregate!");
}
} 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).
if (isa<AGGREGATE_TYPE>(type))
C.HandleAggregateShadowResult(Ty->getPointerTo(), false);
else
C.HandleScalarShadowResult(Ty->getPointerTo(), 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 DefaultABI::HandleArgument(tree type, std::vector<Type *> &ScalarElts,
AttrBuilder *AttrBuilder) {
unsigned Size = 0;
bool DontCheckAlignment = false;
Type *Ty = ConvertType(type);
// Figure out if this field is zero bits wide, e.g. {} or [0 x int]. Do
// not include variable sized fields here.
std::vector<Type *> Elts;
if (Ty->isVoidTy()) {
// Handle void explicitly as a {} type.
Type *OpTy = StructType::get(getGlobalContext());
C.HandleScalarArgument(OpTy, type);
ScalarElts.push_back(OpTy);
} else if (isPassedByInvisibleReference(type)) { // variable size -> by-ref.
Type *PtrTy = Ty->getPointerTo();
C.HandleByInvisibleReferenceArgument(PtrTy, type);
ScalarElts.push_back(PtrTy);
} else if (Ty->isVectorTy()) {
if (LLVM_SHOULD_PASS_VECTOR_IN_INTEGER_REGS(type)) {
PassInIntegerRegisters(type, ScalarElts, 0, false);
} else if (LLVM_SHOULD_PASS_VECTOR_USING_BYVAL_ATTR(type)) {
C.HandleByValArgument(Ty, type);
if (AttrBuilder) {
AttrBuilder->addAttribute(Attribute::ByVal);
AttrBuilder->addAlignmentAttr(LLVM_BYVAL_ALIGNMENT(type));
}
} else {
C.HandleScalarArgument(Ty, type);
ScalarElts.push_back(Ty);
}
} else if (LLVM_TRY_PASS_AGGREGATE_CUSTOM(type, ScalarElts,
C.getCallingConv(), &C)) {
// Nothing to do.
} else if (Ty->isSingleValueType()) {
C.HandleScalarArgument(Ty, type);
ScalarElts.push_back(Ty);
} else if (LLVM_SHOULD_PASS_AGGREGATE_AS_FCA(type, Ty)) {
C.HandleFCAArgument(Ty, type);
} else if (LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(
type, Ty, C.getCallingConv(), Elts)) {
if (!LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(
Elts, ScalarElts, C.isShadowReturn(), C.getCallingConv()))
PassInMixedRegisters(Ty, Elts, ScalarElts);
else {
C.HandleByValArgument(Ty, type);
if (AttrBuilder) {
AttrBuilder->addAttribute(Attribute::ByVal);
AttrBuilder->addAlignmentAttr(LLVM_BYVAL_ALIGNMENT(type));
}
}
} else if (LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(type, Ty)) {
C.HandleByValArgument(Ty, type);
if (AttrBuilder) {
AttrBuilder->addAttribute(Attribute::ByVal);
AttrBuilder->addAlignmentAttr(LLVM_BYVAL_ALIGNMENT(type));
}
} else if (LLVM_SHOULD_PASS_AGGREGATE_IN_INTEGER_REGS(type, &Size,
&DontCheckAlignment)) {
PassInIntegerRegisters(type, ScalarElts, Size, DontCheckAlignment);
} else if (isZeroSizedStructOrUnion(type)) {
// Zero sized struct or union, just drop it!
;
} else if (isa<RECORD_TYPE>(type)) {
for (tree Field = TYPE_FIELDS(type); Field; Field = TREE_CHAIN(Field))
if (isa<FIELD_DECL>(Field)) {
const tree Ftype = TREE_TYPE(Field);
unsigned FNo = GetFieldIndex(Field, Ty);
assert(FNo < INT_MAX && "Case not handled yet!");
// Currently, a bvyal type inside a non-byval struct is a zero-length
// object inside a bigger object on x86-64. This type should be
// skipped (but only when it is inside a bigger object).
// (We know there currently are no other such cases active because
// they would hit the assert in FunctionPrologArgumentConversion::
// HandleByValArgument.)
Type *FTy = ConvertType(Ftype);
(void) FTy; // Not used by all ABI macros.
if (!LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(Ftype, FTy)) {
C.EnterField(FNo, Ty);
HandleArgument(TREE_TYPE(Field), ScalarElts);
C.ExitField();
}
}
} else if (isa<COMPLEX_TYPE>(type)) {
C.EnterField(0, Ty);
HandleArgument(TREE_TYPE(type), ScalarElts);
C.ExitField();
C.EnterField(1, Ty);
HandleArgument(TREE_TYPE(type), ScalarElts);
C.ExitField();
} else if ((isa<UNION_TYPE>(type)) || (isa<QUAL_UNION_TYPE>(type))) {
HandleUnion(type, ScalarElts);
} else if (isa<ARRAY_TYPE>(type)) {
// Array with padding?
if (Ty->isStructTy())
Ty = cast<StructType>(Ty)->getTypeAtIndex(0U);
ArrayType *ATy = cast<ArrayType>(Ty);
for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {
C.EnterField(i, Ty);
HandleArgument(TREE_TYPE(type), ScalarElts);
C.ExitField();
}
} else {
llvm_unreachable("Unknown aggregate type!");
}
}
/// HandleUnion - Handle a UNION_TYPE or QUAL_UNION_TYPE tree.
void DefaultABI::HandleUnion(tree type, std::vector<Type *> &ScalarElts) {
if (TYPE_TRANSPARENT_AGGR(type)) {
tree Field = TYPE_FIELDS(type);
assert(Field && "Transparent union must have some elements!");
while (!isa<FIELD_DECL>(Field)) {
Field = TREE_CHAIN(Field);
assert(Field && "Transparent union must have some elements!");
}
HandleArgument(TREE_TYPE(Field), ScalarElts);
} else {
// Unions pass the largest element.
unsigned MaxSize = 0;
tree MaxElt = 0;
for (tree Field = TYPE_FIELDS(type); Field; Field = TREE_CHAIN(Field)) {
if (isa<FIELD_DECL>(Field)) {
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), 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 DefaultABI::PassInIntegerRegisters(
tree type, std::vector<Type *> &ScalarElts, unsigned origSize,
bool DontCheckAlignment) {
unsigned Size;
if (origSize)
Size = origSize;
else
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 =
getDataLayout().getABITypeAlignment(Type::getInt64Ty(getGlobalContext()));
bool UseInt64 = (DontCheckAlignment || Align >= Int64Align);
unsigned ElementSize = UseInt64 ? 8 : 4;
unsigned ArraySize = Size / ElementSize;
// Put as much of the aggregate as possible into an array.
Type *ATy = NULL;
Type *ArrayElementType = NULL;
if (ArraySize) {
Size = Size % ElementSize;
ArrayElementType = (UseInt64 ? Type::getInt64Ty(getGlobalContext())
: Type::getInt32Ty(getGlobalContext()));
ATy = ArrayType::get(ArrayElementType, ArraySize);
}
// Pass any leftover bytes as a separate element following the array.
unsigned LastEltRealSize = 0;
llvm::Type *LastEltTy = 0;
if (Size > 4) {
LastEltTy = Type::getInt64Ty(getGlobalContext());
} else if (Size > 2) {
LastEltTy = Type::getInt32Ty(getGlobalContext());
} else if (Size > 1) {
LastEltTy = Type::getInt16Ty(getGlobalContext());
} else if (Size > 0) {
LastEltTy = Type::getInt8Ty(getGlobalContext());
}
if (LastEltTy) {
if (Size != getDataLayout().getTypeAllocSize(LastEltTy))
LastEltRealSize = Size;
}
std::vector<Type *> Elts;
if (ATy)
Elts.push_back(ATy);
if (LastEltTy)
Elts.push_back(LastEltTy);
StructType *STy = StructType::get(getGlobalContext(), 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);
ScalarElts.push_back(ArrayElementType);
C.ExitField();
}
C.ExitField();
++i;
}
if (LastEltTy) {
C.EnterField(i, STy);
C.HandleScalarArgument(LastEltTy, 0, LastEltRealSize);
ScalarElts.push_back(LastEltTy);
C.ExitField();
}
}
/// 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 DefaultABI::PassInMixedRegisters(Type *Ty, std::vector<Type *> &OrigElts,
std::vector<Type *> &ScalarElts) {
// We use VoidTy in OrigElts to mean "this is a word in the aggregate
// that occupies storage but has no useful information, and is not passed
// anywhere". Happens on x86-64.
std::vector<Type *> Elts(OrigElts);
Type *wordType = getDataLayout().getPointerSize(0) == 4
? Type::getInt32Ty(getGlobalContext())
: Type::getInt64Ty(getGlobalContext());
for (unsigned i = 0, e = Elts.size(); i != e; ++i)
if (OrigElts[i]->isVoidTy())
Elts[i] = wordType;
StructType *STy = StructType::get(getGlobalContext(), Elts, false);
unsigned Size = getDataLayout().getTypeAllocSize(STy);
unsigned InSize = 0;
// If Ty and STy size does not match then last element is accessing
// extra bits.
unsigned LastEltSizeDiff = 0;
if (isa<StructType>(Ty) || isa<ArrayType>(Ty)) {
InSize = getDataLayout().getTypeAllocSize(Ty);
if (InSize < Size) {
unsigned N = STy->getNumElements();
llvm::Type *LastEltTy = STy->getElementType(N - 1);
if (LastEltTy->isIntegerTy())
LastEltSizeDiff =
getDataLayout().getTypeAllocSize(LastEltTy) - (Size - InSize);
}
}
for (unsigned i = 0, e = Elts.size(); i != e; ++i) {
if (!OrigElts[i]->isVoidTy()) {
C.EnterField(i, STy);
unsigned RealSize = 0;
if (LastEltSizeDiff && i == (e - 1))
RealSize = LastEltSizeDiff;
C.HandleScalarArgument(Elts[i], 0, RealSize);
ScalarElts.push_back(Elts[i]);
C.ExitField();
}
}
}