mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 18:33:14 +01:00
Updated ABI handling to be more flexible with regard to reusing lvalues and allocating fewer temporaries.
This commit is contained in:
53
gen/abi.cpp
53
gen/abi.cpp
@@ -9,9 +9,19 @@
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/abi.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/dvalue.h"
|
||||
|
||||
#include "ir/irfunction.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ABIRewrite::getL(Type* dty, DValue* v, llvm::Value* lval)
|
||||
{
|
||||
LLValue* rval = v->getRVal();
|
||||
assert(rval->getType() == lval->getType()->getContainedType(0));
|
||||
DtoStore(rval, lval);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////// X86 ////////////////////////////
|
||||
@@ -21,13 +31,13 @@
|
||||
// simply swap of real/imag parts for proper x87 complex abi
|
||||
struct X87_complex_swap : ABIRewrite
|
||||
{
|
||||
LLValue* get(Type*, LLValue* v)
|
||||
LLValue* get(Type*, DValue* v)
|
||||
{
|
||||
return DtoAggrPairSwap(v);
|
||||
return DtoAggrPairSwap(v->getRVal());
|
||||
}
|
||||
LLValue* put(Type*, LLValue* v)
|
||||
LLValue* put(Type*, DValue* v)
|
||||
{
|
||||
return DtoAggrPairSwap(v);
|
||||
return DtoAggrPairSwap(v->getRVal());
|
||||
}
|
||||
const LLType* type(Type*, const LLType* t)
|
||||
{
|
||||
@@ -40,8 +50,10 @@ struct X87_complex_swap : ABIRewrite
|
||||
struct X86_cfloat_rewrite : ABIRewrite
|
||||
{
|
||||
// i64 -> {float,float}
|
||||
LLValue* get(Type*, LLValue* in)
|
||||
LLValue* get(Type*, DValue* dv)
|
||||
{
|
||||
LLValue* in = dv->getRVal();
|
||||
|
||||
// extract real part
|
||||
LLValue* rpart = gIR->ir->CreateTrunc(in, LLType::Int32Ty);
|
||||
rpart = gIR->ir->CreateBitCast(rpart, LLType::FloatTy, ".re");
|
||||
@@ -56,8 +68,10 @@ struct X86_cfloat_rewrite : ABIRewrite
|
||||
}
|
||||
|
||||
// {float,float} -> i64
|
||||
LLValue* put(Type*, LLValue* v)
|
||||
LLValue* put(Type*, DValue* dv)
|
||||
{
|
||||
LLValue* v = dv->getRVal();
|
||||
|
||||
// extract real
|
||||
LLValue* r = gIR->ir->CreateExtractValue(v, 0);
|
||||
// cast to i32
|
||||
@@ -95,20 +109,29 @@ struct X86_cfloat_rewrite : ABIRewrite
|
||||
struct X86_struct_to_register : ABIRewrite
|
||||
{
|
||||
// int -> struct
|
||||
LLValue* get(Type* dty, LLValue* v)
|
||||
LLValue* get(Type* dty, DValue* dv)
|
||||
{
|
||||
Logger::println("rewriting int -> struct");
|
||||
LLValue* mem = DtoAlloca(DtoType(dty), ".int_to_struct");
|
||||
LLValue* v = dv->getRVal();
|
||||
DtoStore(v, DtoBitCast(mem, getPtrToType(v->getType())));
|
||||
return DtoLoad(mem);
|
||||
}
|
||||
// int -> struct (with dst lvalue given)
|
||||
void getL(Type* dty, DValue* dv, llvm::Value* lval)
|
||||
{
|
||||
Logger::println("rewriting int -> struct");
|
||||
LLValue* v = dv->getRVal();
|
||||
DtoStore(v, DtoBitCast(lval, getPtrToType(v->getType())));
|
||||
}
|
||||
// struct -> int
|
||||
LLValue* put(Type* dty, LLValue* v)
|
||||
LLValue* put(Type* dty, DValue* dv)
|
||||
{
|
||||
Logger::println("rewriting struct -> int");
|
||||
LLValue* mem = DtoAlloca(v->getType(), ".struct_to_int");
|
||||
DtoStore(v, mem);
|
||||
DtoLoad(DtoBitCast(mem, getPtrToType(type(dty, v->getType()))));
|
||||
assert(dv->isLVal());
|
||||
LLValue* mem = dv->getLVal();
|
||||
const LLType* t = LLIntegerType::get(dty->size()*8);
|
||||
DtoLoad(DtoBitCast(mem, getPtrToType(t)));
|
||||
}
|
||||
const LLType* type(Type*, const LLType* t)
|
||||
{
|
||||
@@ -241,8 +264,10 @@ struct X86TargetABI : TargetABI
|
||||
struct X86_64_cfloat_rewrite : ABIRewrite
|
||||
{
|
||||
// {double} -> {float,float}
|
||||
LLValue* get(Type*, LLValue* in)
|
||||
LLValue* get(Type*, DValue* dv)
|
||||
{
|
||||
LLValue* in = dv->getRVal();
|
||||
|
||||
// extract double
|
||||
LLValue* v = gIR->ir->CreateExtractValue(in, 0);
|
||||
// cast to i64
|
||||
@@ -262,8 +287,10 @@ struct X86_64_cfloat_rewrite : ABIRewrite
|
||||
}
|
||||
|
||||
// {float,float} -> {double}
|
||||
LLValue* put(Type*, LLValue* v)
|
||||
LLValue* put(Type*, DValue* dv)
|
||||
{
|
||||
LLValue* v = dv->getRVal();
|
||||
|
||||
// extract real
|
||||
LLValue* r = gIR->ir->CreateExtractValue(v, 0);
|
||||
// cast to i32
|
||||
|
||||
16
gen/abi.h
16
gen/abi.h
@@ -5,6 +5,8 @@
|
||||
|
||||
struct Type;
|
||||
struct IrFuncTyArg;
|
||||
struct DValue;
|
||||
|
||||
namespace llvm
|
||||
{
|
||||
class Type;
|
||||
@@ -14,13 +16,17 @@ namespace llvm
|
||||
// return rewrite rule
|
||||
struct ABIRewrite
|
||||
{
|
||||
// get original value from rewritten one
|
||||
virtual LLValue* get(Type* dty, LLValue* v) = 0;
|
||||
/// get a rewritten value back to its original form
|
||||
virtual LLValue* get(Type* dty, DValue* v) = 0;
|
||||
|
||||
// rewrite original value
|
||||
virtual LLValue* put(Type* dty, LLValue* v) = 0;
|
||||
/// 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
|
||||
virtual void getL(Type* dty, DValue* v, llvm::Value* lval);
|
||||
|
||||
// returns target type of this rewrite
|
||||
/// put out rewritten value
|
||||
virtual LLValue* put(Type* dty, DValue* v) = 0;
|
||||
|
||||
/// should return the transformed type for this rewrite
|
||||
virtual const LLType* type(Type* dty, const LLType* t) = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -684,9 +684,6 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||
IrLocal* irloc = vd->ir.irLocal;
|
||||
assert(irloc);
|
||||
|
||||
// let the abi transform the argument back first
|
||||
LLValue* argvalue = f->fty->getParam(vd->type, i, irloc->value);
|
||||
|
||||
#if DMDV2
|
||||
if (vd->nestedrefs.dim)
|
||||
#else
|
||||
@@ -701,11 +698,17 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||
|
||||
if (!refout && (!f->fty->args[i]->byref || lazy))
|
||||
{
|
||||
LLValue* a = argvalue;
|
||||
LLValue* v = DtoAlloca(a->getType(), vd->ident->toChars());
|
||||
DtoStore(a,v);
|
||||
irloc->value = v;
|
||||
// alloca a stack slot for this first class value arg
|
||||
LLValue* mem = DtoAlloca(DtoType(vd->type), vd->ident->toChars());
|
||||
|
||||
// let the abi transform the argument back first
|
||||
DImValue arg_dval(vd->type, irloc->value);
|
||||
f->fty->getParam(vd->type, i, &arg_dval, mem);
|
||||
|
||||
// set the arg var value to the alloca
|
||||
irloc->value = mem;
|
||||
}
|
||||
|
||||
if (global.params.symdebug && !(isaArgument(irloc->value) && !isaArgument(irloc->value)->hasByValAttr()) && !refout)
|
||||
DtoDwarfLocalVariable(irloc->value, vd);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@ void ReturnStatement::toIR(IRState* p)
|
||||
// emit dbg line
|
||||
if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum);
|
||||
|
||||
// FIXME: is there ever a case where a sret return needs to be rewritten for the ABI?
|
||||
|
||||
// get return pointer
|
||||
DValue* rvar = new DVarValue(f->type->next, f->decl->ir.irFunc->retArg);
|
||||
DValue* e = exp->toElem(p);
|
||||
@@ -88,12 +90,9 @@ void ReturnStatement::toIR(IRState* p)
|
||||
else
|
||||
{
|
||||
if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum);
|
||||
DValue* e = exp->toElem(p);
|
||||
LLValue* v = e->getRVal();
|
||||
delete e;
|
||||
|
||||
// do abi specific transformations on the return value
|
||||
v = p->func()->type->fty->putRet(exp->type, v);
|
||||
LLValue* v = p->func()->type->fty->putRet(exp->type, exp->toElem(p));
|
||||
|
||||
if (Logger::enabled())
|
||||
Logger::cout() << "return value is '" <<*v << "'\n";
|
||||
|
||||
@@ -380,12 +380,11 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
|
||||
Argument* fnarg = Argument::getNth(tf->parameters, i);
|
||||
assert(fnarg);
|
||||
DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
|
||||
LLValue* arg = argval->getRVal();
|
||||
|
||||
int j = tf->fty->reverseParams ? beg + n - i - 1 : beg + i;
|
||||
|
||||
// give the ABI a say
|
||||
arg = tf->fty->putParam(argval->getType(), i, arg);
|
||||
LLValue* arg = tf->fty->putParam(argval->getType(), i, argval);
|
||||
|
||||
int j = tf->fty->reverseParams ? beg + n - i - 1 : beg + i;
|
||||
|
||||
// parameter type mismatch, this is hard to get rid of
|
||||
if (arg->getType() != callableTy->getParamType(j))
|
||||
@@ -483,7 +482,8 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
|
||||
else if (!retinptr)
|
||||
{
|
||||
// do abi specific return value fixups
|
||||
retllval = tf->fty->getRet(tf->next, retllval);
|
||||
DImValue dretval(tf->next, retllval);
|
||||
retllval = tf->fty->getRet(tf->next, &dretval);
|
||||
}
|
||||
|
||||
// repaint the type if necessary
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "gen/llvm.h"
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/abi.h"
|
||||
#include "gen/dvalue.h"
|
||||
#include "ir/irfunction.h"
|
||||
|
||||
#include <sstream>
|
||||
@@ -23,36 +24,49 @@ IrFuncTyArg::IrFuncTyArg(Type* t, bool bref, unsigned a)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
llvm::Value* IrFuncTy::putRet(Type* dty, llvm::Value* val)
|
||||
llvm::Value* IrFuncTy::putRet(Type* dty, DValue* val)
|
||||
{
|
||||
assert(!arg_sret);
|
||||
if (ret->rewrite)
|
||||
return ret->rewrite->put(dty, val);
|
||||
return val;
|
||||
return val->getRVal();
|
||||
}
|
||||
|
||||
llvm::Value* IrFuncTy::getRet(Type* dty, llvm::Value* val)
|
||||
llvm::Value* IrFuncTy::getRet(Type* dty, DValue* val)
|
||||
{
|
||||
assert(!arg_sret);
|
||||
if (ret->rewrite)
|
||||
return ret->rewrite->get(dty, val);
|
||||
return val;
|
||||
return val->getRVal();
|
||||
}
|
||||
|
||||
llvm::Value* IrFuncTy::putParam(Type* dty, int idx, llvm::Value* val)
|
||||
llvm::Value* IrFuncTy::putParam(Type* dty, int idx, DValue* val)
|
||||
{
|
||||
assert(idx >= 0 && idx < args.size() && "invalid putParam");
|
||||
if (args[idx]->rewrite)
|
||||
return args[idx]->rewrite->put(dty, val);
|
||||
return val;
|
||||
return val->getRVal();
|
||||
}
|
||||
|
||||
llvm::Value* IrFuncTy::getParam(Type* dty, int idx, llvm::Value* val)
|
||||
llvm::Value* IrFuncTy::getParam(Type* dty, int idx, DValue* val)
|
||||
{
|
||||
assert(idx >= 0 && idx < args.size() && "invalid getParam");
|
||||
if (args[idx]->rewrite)
|
||||
return args[idx]->rewrite->get(dty, val);
|
||||
return val;
|
||||
return val->getRVal();
|
||||
}
|
||||
|
||||
void IrFuncTy::getParam(Type* dty, int idx, DValue* val, llvm::Value* lval)
|
||||
{
|
||||
assert(idx >= 0 && idx < args.size() && "invalid getParam");
|
||||
|
||||
if (args[idx]->rewrite)
|
||||
{
|
||||
args[idx]->rewrite->getL(dty, val, lval);
|
||||
return;
|
||||
}
|
||||
|
||||
DtoStore(val->getRVal(), lval);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -19,33 +19,34 @@ struct IrFuncTyArg : IrBase
|
||||
* May NOT be rewritten!!! */
|
||||
Type* type;
|
||||
|
||||
/// This is the final LLVM Type used for the parameter/returnvalue type
|
||||
/// This is the final LLVM Type used for the parameter/return value type
|
||||
const llvm::Type* ltype;
|
||||
|
||||
/** These are the final llvm attributes needed
|
||||
* must be valid for the LLVM Type and byref setting */
|
||||
/** These are the final LLVM attributes used for the function.
|
||||
* Must be valid for the LLVM Type and byref setting */
|
||||
unsigned attrs;
|
||||
|
||||
/** true if the argument final argument is a reference argument
|
||||
* must be true when the D Type is a value type, but the final
|
||||
* LLVM Type is a reference type */
|
||||
/** 'true' if the final LLVM argument is a LLVM reference type.
|
||||
* Must be true when the D Type is a value type, but the final
|
||||
* LLVM Type is a reference type! */
|
||||
bool byref;
|
||||
|
||||
/** Pointer to the ABIRewrite structure needed to rewrite llvm ValueS
|
||||
* to match the final LLVM Type */
|
||||
/** Pointer to the ABIRewrite structure needed to rewrite LLVM ValueS
|
||||
* to match the final LLVM Type when passing arguments and getting
|
||||
* return values */
|
||||
ABIRewrite* rewrite;
|
||||
|
||||
/// Helper to check is the 'inreg' attribute is set
|
||||
/// Helper to check if the 'inreg' attribute is set
|
||||
bool isInReg() const { return (attrs & llvm::Attribute::InReg) != 0; }
|
||||
/// Helper to check is the 'sret' attribute is set
|
||||
/// Helper to check if the 'sret' attribute is set
|
||||
bool isSRet() const { return (attrs & llvm::Attribute::StructRet) != 0; }
|
||||
/// Helper to check is the 'byval' attribute is set
|
||||
/// Helper to check if the 'byval' attribute is set
|
||||
bool isByVal() const { return (attrs & llvm::Attribute::ByVal) != 0; }
|
||||
|
||||
/** Constructor
|
||||
* @param t D type of argument/returnvalue as known by the frontend
|
||||
* @param byref Initial value for the 'byref' field. If true the initial LLVM Type will be of type->pointerTo()
|
||||
*/
|
||||
/** @param t D type of argument/return value as known by the frontend
|
||||
* @param byref Initial value for the 'byref' field. If true the initial
|
||||
* LLVM Type will be of DtoType(type->pointerTo()), instead
|
||||
* of just DtoType(type) */
|
||||
IrFuncTyArg(Type* t, bool byref, unsigned a = 0);
|
||||
};
|
||||
|
||||
@@ -82,11 +83,12 @@ struct IrFuncTy : IrBase
|
||||
reverseParams(false)
|
||||
{}
|
||||
|
||||
llvm::Value* putRet(Type* dty, llvm::Value* val);
|
||||
llvm::Value* getRet(Type* dty, llvm::Value* val);
|
||||
llvm::Value* putRet(Type* dty, DValue* dval);
|
||||
llvm::Value* getRet(Type* dty, DValue* dval);
|
||||
|
||||
llvm::Value* getParam(Type* dty, int idx, llvm::Value* val);
|
||||
llvm::Value* putParam(Type* dty, int idx, llvm::Value* val);
|
||||
llvm::Value* putParam(Type* dty, int idx, DValue* dval);
|
||||
llvm::Value* getParam(Type* dty, int idx, DValue* dval);
|
||||
void getParam(Type* dty, int idx, DValue* dval, llvm::Value* lval);
|
||||
};
|
||||
|
||||
// represents a function
|
||||
|
||||
Reference in New Issue
Block a user