Updated ABI handling to be more flexible with regard to reusing lvalues and allocating fewer temporaries.

This commit is contained in:
Tomas Lindquist Olsen
2009-03-04 17:24:25 +01:00
parent ca41cb29d9
commit 65ba1d4d88
7 changed files with 112 additions and 61 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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