Skip to content

Commit 31e2c3e

Browse files
committed
Fix Win64 ABI wrt. passing structs > 64 bit
1 parent e7fed93 commit 31e2c3e

File tree

1 file changed

+45
-20
lines changed

1 file changed

+45
-20
lines changed

gen/abi-win64.cpp

+45-20
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,29 @@
3636
static bool canRewriteAsInt(Type* t)
3737
{
3838
unsigned size = t->size();
39-
return size <= 8 &&
40-
(size == 1 || size == 2 || size == 4 || size == 8) &&
41-
(t->ty == Tstruct || t->ty == Tsarray);
39+
return size == 1 || size == 2 || size == 4 || size == 8;
40+
}
41+
42+
// Returns true if the D type is a composite (struct or static array).
43+
static bool isComposite(const Type* t)
44+
{
45+
return t->ty == Tstruct || t->ty == Tsarray;
46+
}
4247

48+
// Returns true if the D type is passed byval (the callee getting a pointer
49+
// to a dedicated hidden copy).
50+
static bool isPassedWithByvalSemantics(Type* t)
51+
{
52+
return
53+
// * structs and static arrays which can NOT be rewritten as integers
54+
(isComposite(t) && !canRewriteAsInt(t)) ||
55+
// * 80-bit real and ireal
56+
(t->ty == Tfloat80 || t->ty == Timaginary80) ||
57+
// * cdouble and creal
58+
(t->ty == Tcomplex64 || t->ty == Tcomplex80);
4359
}
4460

4561
// FIXME: This should actually be handled by LLVM and the ByVal arg attribute.
46-
// Implements byval argument passing for scalar non-struct types.
4762
struct Win64_byval_rewrite : ABIRewrite
4863
{
4964
// Get instance from pointer.
@@ -60,8 +75,9 @@ struct Win64_byval_rewrite : ABIRewrite
6075
DtoStore(DtoLoad(ptr), lval); // *lval = *ptr
6176
}
6277

63-
// Turn an instance into a pointer (to a private copy for the callee,
64-
// allocated by the caller).
78+
// Convert the caller's instance to a pointer for the callee.
79+
// The pointer points to a dedicated copy for the callee which
80+
// is allocated by the caller.
6581
LLValue* put(Type* dty, DValue* v)
6682
{
6783
/* NOTE: probably not safe
@@ -71,12 +87,25 @@ struct Win64_byval_rewrite : ABIRewrite
7187
*/
7288

7389
LLValue* original = v->getRVal();
74-
LLValue* copy = DtoRawAlloca(original->getType(), 16, "copy_for_callee");
75-
DtoStore(original, copy); // *copy = *original
90+
LLValue* copy;
91+
92+
llvm::Type* type = original->getType();
93+
if (type->isPointerTy())
94+
{
95+
type = type->getPointerElementType();
96+
copy = DtoRawAlloca(type, 16, "copy_for_callee");
97+
DtoStore(DtoLoad(original), copy); // *copy = *original
98+
}
99+
else
100+
{
101+
copy = DtoRawAlloca(type, 16, "copy_for_callee");
102+
DtoStore(original, copy); // *copy = original
103+
}
104+
76105
return copy;
77106
}
78107

79-
/// should return the transformed type for this rewrite
108+
// T => T*
80109
LLType* type(Type* dty, LLType* t)
81110
{
82111
return getPtrToType(DtoType(dty));
@@ -134,22 +163,17 @@ bool Win64TargetABI::returnInArg(TypeFunction* tf)
134163
// everything <= 64 bits and of a size that is a power of 2
135164
// is returned in a register (RAX, or XMM0 for single float/
136165
// double) - except for cfloat
137-
// real/ireal is returned on top of the x87 stack: ST(0)
166+
// 80-bit real/ireal is returned on top of the x87 stack: ST(0)
138167
// complex numbers are returned in XMM0 & XMM1 (cfloat, cdouble)
139168
// or ST(1) & ST(0) (creal)
140169
// all other structs and static arrays are returned by struct-return (sret)
141-
return (rt->ty == Tstruct
142-
|| rt->ty == Tsarray
143-
) && !canRewriteAsInt(rt);
170+
return isComposite(rt) && !canRewriteAsInt(rt);
144171
}
145172

146173
bool Win64TargetABI::passByVal(Type* t)
147174
{
148175
t = t->toBasetype();
149-
150-
// structs and static arrays are passed byval unless they can be
151-
// rewritten as integers
152-
return (t->ty == Tstruct || t->ty == Tsarray) && !canRewriteAsInt(t);
176+
return isPassedWithByvalSemantics(t);
153177
}
154178

155179
void Win64TargetABI::rewriteFunctionType(TypeFunction* tf, IrFuncTy &fty)
@@ -168,7 +192,7 @@ void Win64TargetABI::rewriteFunctionType(TypeFunction* tf, IrFuncTy &fty)
168192
// the other complex number types are returned via XMM0 = re and XMM1 = im
169193
fty.ret->rewrite = &swapComplex;
170194
}
171-
else if (canRewriteAsInt(rt))
195+
else if (isComposite(rt) && canRewriteAsInt(rt))
172196
{
173197
fty.ret->rewrite = &compositeToInt;
174198
fty.ret->ltype = compositeToInt.type(fty.ret->type, fty.ret->ltype);
@@ -195,12 +219,13 @@ void Win64TargetABI::rewriteFunctionType(TypeFunction* tf, IrFuncTy &fty)
195219
arg.rewrite = &cfloatToInt;
196220
arg.ltype = cfloatToInt.type(arg.type, arg.ltype);
197221
}
198-
else if (canRewriteAsInt(ty))
222+
else if (isComposite(ty) && canRewriteAsInt(ty))
199223
{
200224
arg.rewrite = &compositeToInt;
201225
arg.ltype = compositeToInt.type(arg.type, arg.ltype);
202226
}
203-
else if (ty->iscomplex() || ty->ty == Tfloat80 || ty->ty == Timaginary80)
227+
// FIXME: this should actually be handled by LLVM and the ByVal arg attribute
228+
else if (isPassedWithByvalSemantics(ty))
204229
{
205230
// these types are passed byval:
206231
// the caller allocates a copy and then passes a pointer to the copy

0 commit comments

Comments
 (0)