mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 18:33:14 +01:00
Support for Windows x64 ABI.
This commit is contained in:
@@ -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.
|
* Rewrites a composite type parameter to an integer of the same size.
|
||||||
*
|
*
|
||||||
|
|||||||
223
gen/abi-win64.cpp
Normal file
223
gen/abi-win64.cpp
Normal file
@@ -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 <cassert>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
gen/abi-win64.h
Normal file
24
gen/abi-win64.h
Normal file
@@ -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
|
||||||
@@ -19,63 +19,11 @@
|
|||||||
#include "ir/irfunction.h"
|
#include "ir/irfunction.h"
|
||||||
#include "ir/irfuncty.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
|
struct X86TargetABI : TargetABI
|
||||||
{
|
{
|
||||||
X87_complex_swap swapComplex;
|
X87_complex_swap swapComplex;
|
||||||
X86_cfloat_rewrite cfloatToInt;
|
CfloatToInt cfloatToInt;
|
||||||
CompositeToInt compositeToInt;
|
CompositeToInt compositeToInt;
|
||||||
|
|
||||||
bool returnInArg(TypeFunction* tf)
|
bool returnInArg(TypeFunction* tf)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "mars.h"
|
#include "mars.h"
|
||||||
#include "gen/abi-generic.h"
|
#include "gen/abi-generic.h"
|
||||||
#include "gen/abi-ppc64.h"
|
#include "gen/abi-ppc64.h"
|
||||||
|
#include "gen/abi-win64.h"
|
||||||
#include "gen/abi-x86-64.h"
|
#include "gen/abi-x86-64.h"
|
||||||
#include "gen/abi-x86.h"
|
#include "gen/abi-x86.h"
|
||||||
#include "gen/dvalue.h"
|
#include "gen/dvalue.h"
|
||||||
@@ -71,7 +72,10 @@ TargetABI * TargetABI::getTarget()
|
|||||||
case llvm::Triple::x86:
|
case llvm::Triple::x86:
|
||||||
return getX86TargetABI();
|
return getX86TargetABI();
|
||||||
case llvm::Triple::x86_64:
|
case llvm::Triple::x86_64:
|
||||||
return getX86_64TargetABI();
|
if (global.params.targetTriple.isOSWindows())
|
||||||
|
return getWin64TargetABI();
|
||||||
|
else
|
||||||
|
return getX86_64TargetABI();
|
||||||
case llvm::Triple::ppc64:
|
case llvm::Triple::ppc64:
|
||||||
return getPPC64TargetABI();
|
return getPPC64TargetABI();
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user