ldc/gen/abi-generic.h
Martin 01e3e372fa Win64 ABI fix: return non-POD structs via sret.
And get rid of obsolete integer rewrites on Win64 and PPC.
2015-02-28 22:51:51 +01:00

242 lines
7.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===-- gen/abi-generic.h - Generic Target ABI helpers ----------*- C++ -*-===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
//
// Contains helpers for handling rewrites common to more than one target ABI.
//
//===----------------------------------------------------------------------===//
#ifndef LDC_GEN_ABI_GENERIC_H
#define LDC_GEN_ABI_GENERIC_H
#include "gen/abi.h"
#include "gen/irstate.h"
#include "gen/llvmhelpers.h"
#include "gen/logger.h"
#include "gen/structs.h"
#include "gen/tollvm.h"
struct LLTypeMemoryLayout
{
// Structs and static arrays are folded recursively to scalars or anonymous structs.
// Pointer types are folded to an integer type.
static LLType* fold(LLType* type)
{
// T* => integer
if (type->isPointerTy())
return LLIntegerType::get(gIR->context(), getTypeBitSize(type));
if (LLStructType* structType = isaStruct(type))
{
unsigned numElements = structType->getNumElements();
// fold each element
std::vector<LLType*> elements;
elements.reserve(numElements);
for (unsigned i = 0; i < numElements; ++i)
elements.push_back(fold(structType->getElementType(i)));
// single element? then discard wrapping struct
if (numElements == 1)
return elements[0];
return LLStructType::get(gIR->context(), elements, structType->isPacked());
}
if (LLArrayType* arrayType = isaArray(type))
{
unsigned numElements = arrayType->getNumElements();
LLType* foldedElementType = fold(arrayType->getElementType());
// single element? then fold to scalar
if (numElements == 1)
return foldedElementType;
// otherwise: convert to struct of N folded elements
std::vector<LLType*> elements(numElements, foldedElementType);
return LLStructType::get(gIR->context(), elements);
}
return type;
}
// Checks two LLVM types for memory-layout equivalency.
static bool typesAreEquivalent(LLType* a, LLType* b)
{
if (a == b)
return true;
if (!a || !b)
return false;
return fold(a) == fold(b);
}
};
//////////////////////////////////////////////////////////////////////////////
/// Removes padding fields for (non-union-containing!) structs
struct RemoveStructPadding : ABIRewrite {
/// get a rewritten value back to its original form
LLValue* get(Type* dty, DValue* v) {
LLValue* lval = DtoAlloca(dty, ".rewritetmp");
getL(dty, v, lval);
return lval;
}
/// get a rewritten value back to its original form and store result in provided lvalue
/// this one is optional and defaults to calling the one above
void getL(Type* dty, DValue* v, LLValue* lval) {
// Make sure the padding is zero, so struct comparisons work.
// TODO: Only do this if there's padding, and/or only initialize padding.
DtoMemSetZero(lval, DtoConstSize_t(getTypePaddedSize(DtoType(dty))));
DtoPaddedStruct(dty->toBasetype(), v->getRVal(), lval);
}
/// put out rewritten value
LLValue* put(Type* dty, DValue* v) {
return DtoUnpaddedStruct(dty->toBasetype(), v->getRVal());
}
/// return the transformed type for this rewrite
LLType* type(Type* dty, LLType* t) {
return DtoUnpaddedStructType(dty->toBasetype());
}
};
//////////////////////////////////////////////////////////////////////////////
/**
* Rewrites any parameter to an integer of the same or next bigger size via
* bit-casting.
*/
struct IntegerRewrite : ABIRewrite
{
static LLType* getIntegerType(unsigned minSizeInBytes)
{
if (minSizeInBytes > 8)
return NULL;
unsigned size = minSizeInBytes;
switch (minSizeInBytes) {
case 0:
size = 1;
break;
case 3:
size = 4;
break;
case 5:
case 6:
case 7:
size = 8;
break;
default:
break;
}
return LLIntegerType::get(gIR->context(), size * 8);
}
static bool isObsoleteFor(LLType* llType)
{
if (!llType->isSized()) // e.g., opaque types
{
IF_LOG Logger::cout() << "IntegerRewrite: not rewriting non-sized type "
<< *llType << '\n';
return true;
}
LLType* integerType = getIntegerType(getTypeStoreSize(llType));
return LLTypeMemoryLayout::typesAreEquivalent(llType, integerType);
}
LLValue* get(Type* dty, DValue* dv)
{
LLValue* integer = dv->getRVal();
LLValue* integerDump = storeToMemory(integer, 0, ".IntegerRewrite_dump");
LLType* type = DtoType(dty);
return loadFromMemory(integerDump, type, ".IntegerRewrite_getResult");
}
void getL(Type* dty, DValue* dv, LLValue* lval)
{
LLValue* integer = dv->getRVal();
storeToMemory(integer, lval);
}
LLValue* put(Type* dty, DValue* dv)
{
assert(dty == dv->getType());
LLValue* address = getAddressOf(dv);
LLType* integerType = getIntegerType(dty->size());
return loadFromMemory(address, integerType, ".IntegerRewrite_putResult");
}
LLType* type(Type* t, LLType*)
{
return getIntegerType(t->size());
}
};
//////////////////////////////////////////////////////////////////////////////
/**
* Implements explicit ByVal semantics defined like this:
* Instead of passing a copy of the original argument directly to the callee,
* the caller makes a bit-copy on its stack first and then passes a pointer
* to that copy to the callee.
* The pointer is passed as regular parameter and hence occupies either a
* register or a function arguments stack slot.
*
* This differs from LLVM's ByVal attribute for pointer parameters.
* The ByVal attribute instructs LLVM to pass the pointed-to argument directly
* as a copy on the function arguments stack. In this case, there's no need to
* pass an explicit pointer; the address is implicit.
*/
struct ExplicitByvalRewrite : ABIRewrite
{
const size_t alignment;
ExplicitByvalRewrite(size_t alignment = 16) : alignment(alignment)
{ }
LLValue* get(Type* dty, DValue* v)
{
LLValue* pointer = v->getRVal();
return DtoLoad(pointer, ".ExplicitByvalRewrite_getResult");
}
void getL(Type* dty, DValue* v, LLValue* lval)
{
LLValue* pointer = v->getRVal();
DtoAggrCopy(lval, pointer);
}
LLValue* put(Type* dty, DValue* v)
{
if (DtoIsPassedByRef(dty))
{
LLValue* originalPointer = v->getRVal();
LLType* type = originalPointer->getType()->getPointerElementType();
LLValue* copyForCallee = DtoRawAlloca(type, alignment, ".ExplicitByvalRewrite_putResult");
DtoAggrCopy(copyForCallee, originalPointer);
return copyForCallee;
}
LLValue* originalValue = v->getRVal();
LLValue* copyForCallee = storeToMemory(originalValue, alignment, ".ExplicitByvalRewrite_putResult");
return copyForCallee;
}
LLType* type(Type* dty, LLType* t)
{
return getPtrToType(DtoType(dty));
}
};
#endif