Skip to content

Commit c25b883

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

File tree

1 file changed

+43
-15
lines changed

1 file changed

+43
-15
lines changed

gen/abi-win64.cpp

+43-15
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,26 @@
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.
@@ -71,8 +87,21 @@ 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

@@ -134,22 +163,20 @@ 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();
149176

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);
177+
// FIXME: LLVM doesn't seem to support ByVal on Win64 yet
178+
//return isPassedWithByvalSemantics(t);
179+
return false;
153180
}
154181

155182
void Win64TargetABI::rewriteFunctionType(TypeFunction* tf, IrFuncTy &fty)
@@ -168,7 +195,7 @@ void Win64TargetABI::rewriteFunctionType(TypeFunction* tf, IrFuncTy &fty)
168195
// the other complex number types are returned via XMM0 = re and XMM1 = im
169196
fty.ret->rewrite = &swapComplex;
170197
}
171-
else if (canRewriteAsInt(rt))
198+
else if (isComposite(rt) && canRewriteAsInt(rt))
172199
{
173200
fty.ret->rewrite = &compositeToInt;
174201
fty.ret->ltype = compositeToInt.type(fty.ret->type, fty.ret->ltype);
@@ -195,12 +222,13 @@ void Win64TargetABI::rewriteFunctionType(TypeFunction* tf, IrFuncTy &fty)
195222
arg.rewrite = &cfloatToInt;
196223
arg.ltype = cfloatToInt.type(arg.type, arg.ltype);
197224
}
198-
else if (canRewriteAsInt(ty))
225+
else if (isComposite(ty) && canRewriteAsInt(ty))
199226
{
200227
arg.rewrite = &compositeToInt;
201228
arg.ltype = compositeToInt.type(arg.type, arg.ltype);
202229
}
203-
else if (ty->iscomplex() || ty->ty == Tfloat80 || ty->ty == Timaginary80)
230+
// FIXME: this should actually be handled by LLVM and the ByVal arg attribute
231+
else if (isPassedWithByvalSemantics(ty))
204232
{
205233
// these types are passed byval:
206234
// the caller allocates a copy and then passes a pointer to the copy

0 commit comments

Comments
 (0)