# HG changeset patch # User Tomas Lindquist Olsen # Date 1236183865 -3600 # Node ID 45af482e3832151c59ee2e1b0b1409af11ff4c8d # Parent 9dca7182aa7590196e1d6aa43be09a24634aec5a Updated ABI handling to be more flexible with regard to reusing lvalues and allocating fewer temporaries. diff -r 9dca7182aa75 -r 45af482e3832 gen/abi.cpp --- a/gen/abi.cpp Wed Mar 04 16:13:16 2009 +0100 +++ b/gen/abi.cpp Wed Mar 04 17:24:25 2009 +0100 @@ -9,10 +9,20 @@ #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 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 @@ } // {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_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 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 @@ } // {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 diff -r 9dca7182aa75 -r 45af482e3832 gen/abi.h --- a/gen/abi.h Wed Mar 04 16:13:16 2009 +0100 +++ b/gen/abi.h Wed Mar 04 17:24:25 2009 +0100 @@ -5,6 +5,8 @@ struct Type; struct IrFuncTyArg; +struct DValue; + namespace llvm { class Type; @@ -14,13 +16,17 @@ // 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; }; diff -r 9dca7182aa75 -r 45af482e3832 gen/functions.cpp --- a/gen/functions.cpp Wed Mar 04 16:13:16 2009 +0100 +++ b/gen/functions.cpp Wed Mar 04 17:24:25 2009 +0100 @@ -684,9 +684,6 @@ 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 @@ 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); } diff -r 9dca7182aa75 -r 45af482e3832 gen/statements.cpp --- a/gen/statements.cpp Wed Mar 04 16:13:16 2009 +0100 +++ b/gen/statements.cpp Wed Mar 04 17:24:25 2009 +0100 @@ -68,6 +68,8 @@ // 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 @@ 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"; diff -r 9dca7182aa75 -r 45af482e3832 gen/tocall.cpp --- a/gen/tocall.cpp Wed Mar 04 16:13:16 2009 +0100 +++ b/gen/tocall.cpp Wed Mar 04 17:24:25 2009 +0100 @@ -380,13 +380,12 @@ Argument* fnarg = Argument::getNth(tf->parameters, i); assert(fnarg); DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); - LLValue* arg = argval->getRVal(); + + // give the ABI a say + LLValue* arg = tf->fty->putParam(argval->getType(), i, argval); int j = tf->fty->reverseParams ? beg + n - i - 1 : beg + i; - // give the ABI a say - arg = tf->fty->putParam(argval->getType(), i, arg); - // parameter type mismatch, this is hard to get rid of if (arg->getType() != callableTy->getParamType(j)) { @@ -483,7 +482,8 @@ 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 diff -r 9dca7182aa75 -r 45af482e3832 ir/irfunction.cpp --- a/ir/irfunction.cpp Wed Mar 04 16:13:16 2009 +0100 +++ b/ir/irfunction.cpp Wed Mar 04 17:24:25 2009 +0100 @@ -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 @@ -23,36 +24,49 @@ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -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); } ////////////////////////////////////////////////////////////////////////////// diff -r 9dca7182aa75 -r 45af482e3832 ir/irfunction.h --- a/ir/irfunction.h Wed Mar 04 16:13:16 2009 +0100 +++ b/ir/irfunction.h Wed Mar 04 17:24:25 2009 +0100 @@ -19,33 +19,34 @@ * 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 @@ 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