mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-13 22:48:43 +03:00
Refactoring: Introduce ArgTypesRewrite
This commit is contained in:
parent
d603010159
commit
e9164f1f1a
4 changed files with 73 additions and 79 deletions
|
@ -161,8 +161,20 @@ struct BaseBitcastABIRewrite : ABIRewrite {
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Rewrites any parameter to an integer of the same or next bigger size via
|
||||
* bit-casting.
|
||||
* Bit-casts an argument based on the front-end toArgTypes* machinery.
|
||||
*/
|
||||
struct ArgTypesRewrite : BaseBitcastABIRewrite {
|
||||
LLType *type(Type *t) override {
|
||||
LLType *rewrittenType = TargetABI::getRewrittenArgType(t->toBasetype());
|
||||
assert(rewrittenType);
|
||||
return rewrittenType;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Bit-casts an argument to an integer of the same or next bigger size.
|
||||
*/
|
||||
struct IntegerRewrite : BaseBitcastABIRewrite {
|
||||
static LLType *getIntegerType(unsigned minSizeInBytes) {
|
||||
|
|
|
@ -49,62 +49,6 @@
|
|||
#include <utility>
|
||||
|
||||
namespace {
|
||||
// Structs, static arrays and cfloats may be rewritten to exploit registers.
|
||||
// This function returns the rewritten type, or null if no transformation is
|
||||
// needed.
|
||||
LLType *getAbiType(Type *ty) {
|
||||
// First, check if there's any need of a transformation:
|
||||
if (!(ty->ty == Tcomplex32 || ty->ty == Tstruct || ty->ty == Tsarray)) {
|
||||
return nullptr; // Nothing to do
|
||||
}
|
||||
|
||||
// Okay, we may need to transform. Figure out a canonical type:
|
||||
llvm::SmallVector<Type *, 2> argTypes;
|
||||
|
||||
// try to reuse cached argTypes of StructDeclarations
|
||||
if (ty->ty == Tstruct) {
|
||||
const auto sd = static_cast<TypeStruct *>(ty)->sym;
|
||||
if (sd && sd->sizeok == SIZEOKdone) {
|
||||
const unsigned N = sd->numArgTypes();
|
||||
if (N == 0) {
|
||||
return nullptr; // don't rewrite
|
||||
}
|
||||
for (unsigned i = 0; i < N; ++i) {
|
||||
argTypes.push_back(sd->argType(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (argTypes.empty()) {
|
||||
TypeTuple *tuple = target.toArgTypes(ty);
|
||||
if (!tuple || tuple->arguments->empty()) {
|
||||
return nullptr; // don't rewrite
|
||||
}
|
||||
for (auto param : *tuple->arguments) {
|
||||
argTypes.push_back(param->type);
|
||||
}
|
||||
}
|
||||
|
||||
LLType *abiTy = nullptr;
|
||||
if (argTypes.size() == 1) {
|
||||
abiTy = DtoType(argTypes[0]);
|
||||
} else {
|
||||
abiTy = LLStructType::get(gIR->context(),
|
||||
{DtoType(argTypes[0]), DtoType(argTypes[1])});
|
||||
}
|
||||
|
||||
return abiTy;
|
||||
}
|
||||
|
||||
bool passByVal(Type *ty) {
|
||||
TypeTuple *argTypes = target.toArgTypes(ty);
|
||||
if (!argTypes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return argTypes->arguments->empty(); // empty => cannot be passed in registers
|
||||
}
|
||||
|
||||
struct RegCount {
|
||||
char int_regs, sse_regs;
|
||||
|
||||
|
@ -165,15 +109,6 @@ struct RegCount {
|
|||
return ArgumentFitsIn;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This type performs the actual struct/cfloat rewriting by simply storing to
|
||||
* memory so that it's then readable as the other type (i.e., bit-casting).
|
||||
*/
|
||||
struct X86_64_C_struct_rewrite : BaseBitcastABIRewrite {
|
||||
LLType *type(Type *t) override { return getAbiType(t->toBasetype()); }
|
||||
};
|
||||
|
||||
/**
|
||||
* This type is used to force LLVM to pass a LL aggregate in memory,
|
||||
|
@ -204,9 +139,10 @@ struct ImplicitByvalRewrite : ABIRewrite {
|
|||
arg.attrs.addAlignmentAttr(alignment);
|
||||
}
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
struct X86_64TargetABI : TargetABI {
|
||||
X86_64_C_struct_rewrite struct_rewrite;
|
||||
ArgTypesRewrite argTypesRewrite;
|
||||
ImplicitByvalRewrite byvalRewrite;
|
||||
IndirectByvalRewrite indirectByvalRewrite;
|
||||
|
||||
|
@ -231,6 +167,12 @@ struct X86_64TargetABI : TargetABI {
|
|||
|
||||
private:
|
||||
LLType *getValistType();
|
||||
|
||||
static bool passInMemory(Type* t) {
|
||||
TypeTuple *argTypes = getArgTypes(t);
|
||||
return argTypes && argTypes->arguments->empty();
|
||||
}
|
||||
|
||||
RegCount &getRegCount(IrFuncTy &fty) {
|
||||
return reinterpret_cast<RegCount &>(fty.tag);
|
||||
}
|
||||
|
@ -245,7 +187,7 @@ bool X86_64TargetABI::returnInArg(TypeFunction *tf, bool) {
|
|||
}
|
||||
|
||||
Type *rt = tf->next->toBasetype();
|
||||
return ::passByVal(rt);
|
||||
return passInMemory(rt);
|
||||
}
|
||||
|
||||
bool X86_64TargetABI::passByVal(TypeFunction *tf, Type *t) {
|
||||
|
@ -253,7 +195,7 @@ bool X86_64TargetABI::passByVal(TypeFunction *tf, Type *t) {
|
|||
if (!isPOD(t))
|
||||
return false;
|
||||
|
||||
return ::passByVal(t->toBasetype());
|
||||
return passInMemory(t->toBasetype());
|
||||
}
|
||||
|
||||
void X86_64TargetABI::rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg) {
|
||||
|
@ -275,15 +217,9 @@ void X86_64TargetABI::rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg,
|
|||
return;
|
||||
}
|
||||
|
||||
LLType *abiTy = getAbiType(t);
|
||||
if (abiTy && !LLTypeMemoryLayout::typesAreEquivalent(abiTy, originalLType)) {
|
||||
IF_LOG {
|
||||
Logger::println("Rewriting argument type %s", t->toChars());
|
||||
LOG_SCOPE;
|
||||
Logger::cout() << *originalLType << " => " << *abiTy << '\n';
|
||||
}
|
||||
|
||||
struct_rewrite.applyTo(arg, abiTy);
|
||||
if (t->ty == Tcomplex32 || t->ty == Tstruct || t->ty == Tsarray) {
|
||||
if (LLType *rewrittenType = getRewrittenArgType(t))
|
||||
argTypesRewrite.applyToIfNotObsolete(arg, rewrittenType);
|
||||
}
|
||||
|
||||
if (regCount.trySubtract(arg) == RegCount::ArgumentWouldFitInPartially) {
|
||||
|
|
35
gen/abi.cpp
35
gen/abi.cpp
|
@ -12,6 +12,7 @@
|
|||
#include "dmd/expression.h"
|
||||
#include "dmd/id.h"
|
||||
#include "dmd/identifier.h"
|
||||
#include "dmd/target.h"
|
||||
#include "gen/abi-aarch64.h"
|
||||
#include "gen/abi-arm.h"
|
||||
#include "gen/abi-generic.h"
|
||||
|
@ -67,6 +68,40 @@ bool TargetABI::isHFVA(Type *t, int maxNumElements, LLType **hfvaType) {
|
|||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TypeTuple *TargetABI::getArgTypes(Type *t) {
|
||||
// try to reuse cached argTypes of StructDeclarations
|
||||
if (auto ts = t->toBasetype()->isTypeStruct()) {
|
||||
auto sd = ts->sym;
|
||||
if (sd->sizeok == SIZEOKdone)
|
||||
return sd->argTypes;
|
||||
}
|
||||
|
||||
return target.toArgTypes(t);
|
||||
}
|
||||
|
||||
LLType *TargetABI::getRewrittenArgType(Type *t, TypeTuple *argTypes) {
|
||||
if (!argTypes || argTypes->arguments->empty() ||
|
||||
(argTypes->arguments->length == 1 &&
|
||||
argTypes->arguments->front()->type == t)) {
|
||||
return nullptr; // don't rewrite
|
||||
}
|
||||
|
||||
auto &args = *argTypes->arguments;
|
||||
assert(args.length <= 2);
|
||||
return args.length == 1
|
||||
? DtoType(args[0]->type)
|
||||
: LLStructType::get(gIR->context(), {DtoType(args[0]->type),
|
||||
DtoType(args[1]->type)});
|
||||
}
|
||||
|
||||
LLType *TargetABI::getRewrittenArgType(Type *t) {
|
||||
return getRewrittenArgType(t, getArgTypes(t));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TargetABI::isAggregate(Type *t) {
|
||||
TY ty = t->toBasetype()->ty;
|
||||
// FIXME: dynamic arrays can currently not be rewritten as they are used
|
||||
|
|
11
gen/abi.h
11
gen/abi.h
|
@ -24,6 +24,7 @@
|
|||
class Type;
|
||||
class TypeFunction;
|
||||
class TypeStruct;
|
||||
class TypeTuple;
|
||||
struct IrFuncTy;
|
||||
struct IrFuncTyArg;
|
||||
class FuncDeclaration;
|
||||
|
@ -177,6 +178,11 @@ struct TargetABI {
|
|||
static bool isHFVA(Type *t, int maxNumElements,
|
||||
llvm::Type **hfvaType = nullptr);
|
||||
|
||||
/// Uses the front-end toArgTypes* machinery and returns an appropriate LL
|
||||
/// type if arguments of the specified D type are to be rewritten in order to
|
||||
/// be passed correctly in registers.
|
||||
static llvm::Type *getRewrittenArgType(Type *t);
|
||||
|
||||
protected:
|
||||
|
||||
/// Returns true if the D type is an aggregate:
|
||||
|
@ -196,4 +202,9 @@ protected:
|
|||
/// Returns true if the D function type uses extern(D) linkage *and* isn't a
|
||||
/// D-style variadic function.
|
||||
static bool isExternD(TypeFunction *tf);
|
||||
|
||||
/// Returns the type tuple produced by the front-end's toArgTypes* machinery.
|
||||
static TypeTuple *getArgTypes(Type *t);
|
||||
|
||||
static llvm::Type *getRewrittenArgType(Type *t, TypeTuple *argTypes);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue