diff --git a/gen/abi-generic.h b/gen/abi-generic.h index 995594c3..c5493fa2 100644 --- a/gen/abi-generic.h +++ b/gen/abi-generic.h @@ -71,6 +71,62 @@ struct X87_complex_swap : ABIRewrite ////////////////////////////////////////////////////////////////////////////// +// Rewrites a cfloat (2x32 bits) as 64-bit integer. +// Assumes a little-endian byte order. +struct CfloatToInt : ABIRewrite +{ + // i64 -> {float,float} + LLValue* get(Type*, DValue* dv) + { + LLValue* in = dv->getRVal(); + + // extract real part + LLValue* rpart = gIR->ir->CreateTrunc(in, LLType::getInt32Ty(gIR->context())); + rpart = gIR->ir->CreateBitCast(rpart, LLType::getFloatTy(gIR->context()), ".re"); + + // extract imag part + LLValue* ipart = gIR->ir->CreateLShr(in, LLConstantInt::get(LLType::getInt64Ty(gIR->context()), 32, false)); + ipart = gIR->ir->CreateTrunc(ipart, LLType::getInt32Ty(gIR->context())); + ipart = gIR->ir->CreateBitCast(ipart, LLType::getFloatTy(gIR->context()), ".im"); + + // return {float,float} aggr pair with same bits + return DtoAggrPair(rpart, ipart, ".final_cfloat"); + } + + // {float,float} -> i64 + LLValue* put(Type*, DValue* dv) + { + LLValue* v = dv->getRVal(); + + // extract real + LLValue* r = gIR->ir->CreateExtractValue(v, 0); + // cast to i32 + r = gIR->ir->CreateBitCast(r, LLType::getInt32Ty(gIR->context())); + // zext to i64 + r = gIR->ir->CreateZExt(r, LLType::getInt64Ty(gIR->context())); + + // extract imag + LLValue* i = gIR->ir->CreateExtractValue(v, 1); + // cast to i32 + i = gIR->ir->CreateBitCast(i, LLType::getInt32Ty(gIR->context())); + // zext to i64 + i = gIR->ir->CreateZExt(i, LLType::getInt64Ty(gIR->context())); + // shift up + i = gIR->ir->CreateShl(i, LLConstantInt::get(LLType::getInt64Ty(gIR->context()), 32, false)); + + // combine and return + return v = gIR->ir->CreateOr(r, i); + } + + // {float,float} -> i64 + LLType* type(Type*, LLType* t) + { + return LLType::getInt64Ty(gIR->context()); + } +}; + +////////////////////////////////////////////////////////////////////////////// + /** * Rewrites a composite type parameter to an integer of the same size. * diff --git a/gen/abi-win64.cpp b/gen/abi-win64.cpp new file mode 100644 index 00000000..cf1acbb4 --- /dev/null +++ b/gen/abi-win64.cpp @@ -0,0 +1,223 @@ +//===-- abi-win64.cpp -----------------------------------------------------===// +// +// LDC – the LLVM D compiler +// +// This file is distributed under the BSD-style LDC license. See the LICENSE +// file for details. +// +//===----------------------------------------------------------------------===// +// +// extern(C) implements the C calling convention for x86-64 on Windows, see +// http://msdn.microsoft.com/en-us/library/7kcdt6fy%28v=vs.110%29.aspx +// +//===----------------------------------------------------------------------===// + +#include "mtype.h" +#include "declaration.h" +#include "aggregate.h" + +#include "gen/irstate.h" +#include "gen/llvm.h" +#include "gen/tollvm.h" +#include "gen/logger.h" +#include "gen/dvalue.h" +#include "gen/llvmhelpers.h" +#include "gen/abi.h" +#include "gen/abi-win64.h" +#include "gen/abi-generic.h" +#include "ir/irfunction.h" + +#include +#include +#include + + +// Returns true if the D type can be bit-cast to an integer of the same size. +static bool canRewriteAsInt(Type* t) +{ + unsigned size = t->size(); + return size <= 8 && + (size == 1 || size == 2 || size == 4 || size == 8) && + (t->ty == Tstruct || t->ty == Tsarray); + +} + +// FIXME: This should actually be handled by LLVM and the ByVal arg attribute. +// Implements byval argument passing for scalar non-struct types. +struct Win64_byval_rewrite : ABIRewrite +{ + // Get instance from pointer. + LLValue* get(Type* dty, DValue* v) + { + LLValue* ptr = v->getRVal(); + return DtoLoad(ptr); // *ptr + } + + // Get instance from pointer, and store in the provided location. + void getL(Type* dty, DValue* v, llvm::Value* lval) + { + LLValue* ptr = v->getRVal(); + DtoStore(DtoLoad(ptr), lval); // *lval = *ptr + } + + // Turn an instance into a pointer (to a private copy for the callee, + // allocated by the caller). + LLValue* put(Type* dty, DValue* v) + { + /* NOTE: probably not safe + // optimization: do not copy if parameter is not mutable + if (!dty->isMutable() && v->isLVal()) + return v->getLVal(); + */ + + LLValue* original = v->getRVal(); + LLValue* copy = DtoRawAlloca(original->getType(), 16, "copy_for_callee"); + DtoStore(original, copy); // *copy = *original + return copy; + } + + /// should return the transformed type for this rewrite + LLType* type(Type* dty, LLType* t) + { + return getPtrToType(DtoType(dty)); + } +}; + + +struct Win64TargetABI : TargetABI +{ + Win64_byval_rewrite byval_rewrite; + CompositeToInt compositeToInt; + CfloatToInt cfloatToInt; + X87_complex_swap swapComplex; + + bool returnInArg(TypeFunction* tf); + + bool passByVal(Type* t); + + void rewriteFunctionType(TypeFunction* tf); +}; + + +// The public getter for abi.cpp +TargetABI* getWin64TargetABI() +{ + return new Win64TargetABI; +} + + +bool Win64TargetABI::returnInArg(TypeFunction* tf) +{ +#if DMDV2 + if (tf->isref) + return false; +#endif + + Type* rt = tf->next->toBasetype(); + + // everything <= 64 bits and of a size that is a power of 2 + // is returned in a register (RAX, or XMM0 for single float/ + // double) - except for cfloat + // real/ireal is returned on top of the x87 stack: ST(0) + // complex numbers are returned in XMM0 & XMM1 (cfloat, cdouble) + // or ST(1) & ST(0) (creal) + // all other structs and static arrays are returned by struct-return (sret) + return (rt->ty == Tstruct +#if SARRAYVALUE + || rt->ty == Tsarray +#endif + ) && !canRewriteAsInt(rt); +} + +bool Win64TargetABI::passByVal(Type* t) +{ + t = t->toBasetype(); + + // structs and static arrays are passed byval unless they can be + // rewritten as integers + return (t->ty == Tstruct || t->ty == Tsarray) && !canRewriteAsInt(t); +} + +void Win64TargetABI::rewriteFunctionType(TypeFunction* tf) +{ + IrFuncTy& fty = tf->fty; + Type* rt = fty.ret->type->toBasetype(); + + // RETURN VALUE + +#if DMDV2 + if (!tf->isref) +#endif + { + if (rt->ty == Tcomplex80) + { + // LLVM returns a '{real re, ireal im}' via ST(0) = re and ST(1) = im + // DMD does it the other way around: ST(0) = im and ST(1) = re + // therefore swap the real/imaginary parts + // the other complex number types are returned via XMM0 = re and XMM1 = im + fty.ret->rewrite = &swapComplex; + } + else if (canRewriteAsInt(rt)) + { + fty.ret->rewrite = &compositeToInt; + fty.ret->ltype = compositeToInt.type(fty.ret->type, fty.ret->ltype); + } + } + + // IMPLICIT PARAMETERS + + // EXPLICIT PARAMETERS + + for (IrFuncTy::ArgRIter I = fty.args.rbegin(), E = fty.args.rend(); I != E; ++I) + { + IrFuncTyArg& arg = **I; + + if (arg.byref) + continue; + + Type* ty = arg.type->toBasetype(); + unsigned sz = ty->size(); + + if (ty->ty == Tcomplex32) + { + // {float,float} cannot be bit-cast to int64 (using CompositeToInt) + // FIXME: is there a way to force a bit-cast? + arg.rewrite = &cfloatToInt; + arg.ltype = cfloatToInt.type(arg.type, arg.ltype); + } + else if (canRewriteAsInt(ty)) + { + arg.rewrite = &compositeToInt; + arg.ltype = compositeToInt.type(arg.type, arg.ltype); + } + else if (ty->iscomplex() || ty->ty == Tfloat80 || ty->ty == Timaginary80) + { + // these types are passed byval: + // the caller allocates a copy and then passes a pointer to the copy + // FIXME: use tightly packed struct for creal like DMD? + arg.rewrite = &byval_rewrite; + arg.ltype = byval_rewrite.type(arg.type, arg.ltype); + + // the copy is treated as a local variable of the callee + // hence add the NoAlias and NoCapture attributes +#if LDC_LLVM_VER >= 303 + arg.attrs.clear(); + arg.attrs.addAttribute(llvm::Attribute::NoAlias) + .addAttribute(llvm::Attribute::NoCapture); +#elif LDC_LLVM_VER == 302 + arg.attrs = llvm::Attributes::get(gIR->context(), llvm::AttrBuilder().addAttribute(llvm::Attributes::NoAlias) + .addAttribute(llvm::Attributes::NoCapture)); +#else + arg.attrs = llvm::Attribute::NoAlias | llvm::Attribute::NoCapture; +#endif + } + } + + if (tf->linkage == LINKd) + { + // reverse parameter order + // for non variadics + if (fty.args.size() > 1 && tf->varargs != 1) + fty.reverseParams = true; + } +} diff --git a/gen/abi-win64.h b/gen/abi-win64.h new file mode 100644 index 00000000..580c1c18 --- /dev/null +++ b/gen/abi-win64.h @@ -0,0 +1,24 @@ +//===-- gen/abi-win64.h - Windows x86_64 ABI description --------*- C++ -*-===// +// +// LDC – the LLVM D compiler +// +// This file is distributed under the BSD-style LDC license. See the LICENSE +// file for details. +// +//===----------------------------------------------------------------------===// +// +// The ABI implementation used for 64 bit x86 (i.e. x86_64/AMD64/x64) targets +// on Windows. +// +//===----------------------------------------------------------------------===// + +#ifndef __LDC_GEN_ABI_WIN64_H__ +#define __LDC_GEN_ABI_WIN64_H__ + +#include "gen/abi.h" + + +TargetABI* getWin64TargetABI(); + + +#endif diff --git a/gen/abi-x86.cpp b/gen/abi-x86.cpp index 59edcfa5..b4069f31 100644 --- a/gen/abi-x86.cpp +++ b/gen/abi-x86.cpp @@ -19,63 +19,11 @@ #include "ir/irfunction.h" #include "ir/irfuncty.h" -struct X86_cfloat_rewrite : ABIRewrite -{ - // i64 -> {float,float} - LLValue* get(Type*, DValue* dv) - { - LLValue* in = dv->getRVal(); - - // extract real part - LLValue* rpart = gIR->ir->CreateTrunc(in, LLType::getInt32Ty(gIR->context())); - rpart = gIR->ir->CreateBitCast(rpart, LLType::getFloatTy(gIR->context()), ".re"); - - // extract imag part - LLValue* ipart = gIR->ir->CreateLShr(in, LLConstantInt::get(LLType::getInt64Ty(gIR->context()), 32, false)); - ipart = gIR->ir->CreateTrunc(ipart, LLType::getInt32Ty(gIR->context())); - ipart = gIR->ir->CreateBitCast(ipart, LLType::getFloatTy(gIR->context()), ".im"); - - // return {float,float} aggr pair with same bits - return DtoAggrPair(rpart, ipart, ".final_cfloat"); - } - - // {float,float} -> i64 - LLValue* put(Type*, DValue* dv) - { - LLValue* v = dv->getRVal(); - - // extract real - LLValue* r = gIR->ir->CreateExtractValue(v, 0); - // cast to i32 - r = gIR->ir->CreateBitCast(r, LLType::getInt32Ty(gIR->context())); - // zext to i64 - r = gIR->ir->CreateZExt(r, LLType::getInt64Ty(gIR->context())); - - // extract imag - LLValue* i = gIR->ir->CreateExtractValue(v, 1); - // cast to i32 - i = gIR->ir->CreateBitCast(i, LLType::getInt32Ty(gIR->context())); - // zext to i64 - i = gIR->ir->CreateZExt(i, LLType::getInt64Ty(gIR->context())); - // shift up - i = gIR->ir->CreateShl(i, LLConstantInt::get(LLType::getInt64Ty(gIR->context()), 32, false)); - - // combine and return - return v = gIR->ir->CreateOr(r, i); - } - - // {float,float} -> i64 - LLType* type(Type*, LLType* t) - { - return LLType::getInt64Ty(gIR->context()); - } -}; - struct X86TargetABI : TargetABI { X87_complex_swap swapComplex; - X86_cfloat_rewrite cfloatToInt; + CfloatToInt cfloatToInt; CompositeToInt compositeToInt; bool returnInArg(TypeFunction* tf) diff --git a/gen/abi.cpp b/gen/abi.cpp index 9ec247a3..0152a9c9 100644 --- a/gen/abi.cpp +++ b/gen/abi.cpp @@ -11,6 +11,7 @@ #include "mars.h" #include "gen/abi-generic.h" #include "gen/abi-ppc64.h" +#include "gen/abi-win64.h" #include "gen/abi-x86-64.h" #include "gen/abi-x86.h" #include "gen/dvalue.h" @@ -71,7 +72,10 @@ TargetABI * TargetABI::getTarget() case llvm::Triple::x86: return getX86TargetABI(); case llvm::Triple::x86_64: - return getX86_64TargetABI(); + if (global.params.targetTriple.isOSWindows()) + return getWin64TargetABI(); + else + return getX86_64TargetABI(); case llvm::Triple::ppc64: return getPPC64TargetABI(); default: