Refactoring: Introduce ArgTypesRewrite

This commit is contained in:
Martin Kinkelin 2020-05-03 15:04:18 +02:00
parent d603010159
commit e9164f1f1a
4 changed files with 73 additions and 79 deletions

View file

@ -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) {

View file

@ -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) {

View file

@ -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

View file

@ -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);
};