Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 15955a1

Browse files
authored
Merge pull request #3086 from kinke/stdarg_aarch64
[stable] core.{stdc.stdarg,vararg}: Add support for non-Apple AArch64
2 parents 3961b6e + 3da2ace commit 15955a1

File tree

6 files changed

+217
-18
lines changed

6 files changed

+217
-18
lines changed

mak/COPY

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ COPY=\
5555
\
5656
$(IMPDIR)\core\internal\util\array.d \
5757
\
58+
$(IMPDIR)\core\internal\vararg\aarch64.d \
5859
$(IMPDIR)\core\internal\vararg\sysv_x64.d \
5960
\
6061
$(IMPDIR)\core\stdc\assert_.d \

mak/SRCS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ SRCS=\
5555
\
5656
src\core\internal\util\array.d \
5757
\
58+
src\core\internal\vararg\aarch64.d \
5859
src\core\internal\vararg\sysv_x64.d \
5960
\
6061
src\core\stdc\assert_.d \

src/core/internal/vararg/aarch64.d

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/**
2+
* Varargs implementation for the AArch64 Procedure Call Standard (not followed by Apple).
3+
* Used by core.stdc.stdarg and core.vararg.
4+
*
5+
* Reference: https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst#appendix-variable-argument-lists
6+
*
7+
* Copyright: Copyright Digital Mars 2020 - 2020.
8+
* License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
9+
* Authors: Martin Kinkelin
10+
* Source: $(DRUNTIMESRC core/internal/vararg/aarch64.d)
11+
*/
12+
13+
module core.internal.vararg.aarch64;
14+
15+
version (AArch64):
16+
17+
// Darwin uses a simpler varargs implementation
18+
version (OSX) {}
19+
else version (iOS) {}
20+
else version (TVOS) {}
21+
else version (WatchOS) {}
22+
else:
23+
24+
import core.stdc.stdarg : alignUp;
25+
26+
@system:
27+
//@nogc: // Not yet, need to make TypeInfo's member functions @nogc first
28+
nothrow:
29+
30+
extern (C++, std) struct __va_list
31+
{
32+
void* __stack;
33+
void* __gr_top;
34+
void* __vr_top;
35+
int __gr_offs;
36+
int __vr_offs;
37+
}
38+
39+
///
40+
alias va_list = __va_list;
41+
42+
///
43+
T va_arg(T)(ref va_list ap)
44+
{
45+
static if (is(T ArgTypes == __argTypes))
46+
{
47+
T onStack()
48+
{
49+
void* arg = ap.__stack;
50+
static if (T.alignof > 8)
51+
arg = arg.alignUp!16;
52+
ap.__stack = alignUp(arg + T.sizeof);
53+
version (BigEndian)
54+
static if (T.sizeof < 8)
55+
arg += 8 - T.sizeof;
56+
return *cast(T*) arg;
57+
}
58+
59+
static if (ArgTypes.length == 0)
60+
{
61+
// indirectly by value; get pointer and copy
62+
T* ptr = va_arg!(T*)(ap);
63+
return *ptr;
64+
}
65+
66+
static assert(ArgTypes.length == 1);
67+
68+
static if (is(ArgTypes[0] E : E[N], int N))
69+
alias FundamentalType = E; // static array element type
70+
else
71+
alias FundamentalType = ArgTypes[0];
72+
73+
static if (__traits(isFloating, FundamentalType) || isVectorType!FundamentalType)
74+
{
75+
import core.stdc.string : memcpy;
76+
77+
// SIMD register(s)
78+
int offs = ap.__vr_offs;
79+
if (offs >= 0)
80+
return onStack(); // reg save area empty
81+
enum int usedRegSize = FundamentalType.sizeof;
82+
static assert(T.sizeof % usedRegSize == 0);
83+
enum int nreg = T.sizeof / usedRegSize;
84+
ap.__vr_offs = offs + (nreg * 16);
85+
if (ap.__vr_offs > 0)
86+
return onStack(); // overflowed reg save area
87+
version (BigEndian)
88+
static if (usedRegSize < 16)
89+
offs += 16 - usedRegSize;
90+
91+
T result = void;
92+
static foreach (i; 0 .. nreg)
93+
memcpy((cast(void*) &result) + i * usedRegSize, ap.__vr_top + (offs + i * 16), usedRegSize);
94+
return result;
95+
}
96+
else
97+
{
98+
// GP register(s)
99+
int offs = ap.__gr_offs;
100+
if (offs >= 0)
101+
return onStack(); // reg save area empty
102+
static if (T.alignof > 8)
103+
offs = offs.alignUp!16;
104+
enum int nreg = (T.sizeof + 7) / 8;
105+
ap.__gr_offs = offs + (nreg * 8);
106+
if (ap.__gr_offs > 0)
107+
return onStack(); // overflowed reg save area
108+
version (BigEndian)
109+
static if (T.sizeof < 8)
110+
offs += 8 - T.sizeof;
111+
return *cast(T*) (ap.__gr_top + offs);
112+
}
113+
}
114+
else
115+
{
116+
static assert(false, "not a valid argument type for va_arg");
117+
}
118+
}
119+
120+
///
121+
void va_arg()(ref va_list ap, TypeInfo ti, void* parmn)
122+
{
123+
import core.stdc.string : memcpy;
124+
125+
const size = ti.tsize;
126+
const alignment = ti.talign;
127+
128+
if (auto ti_struct = cast(TypeInfo_Struct) ti)
129+
{
130+
TypeInfo arg1, arg2;
131+
ti.argTypes(arg1, arg2);
132+
133+
if (!arg1)
134+
{
135+
// indirectly by value; get pointer and move
136+
void* ptr = va_arg!(void*)(ap);
137+
memcpy(parmn, ptr, size);
138+
return;
139+
}
140+
141+
assert(!arg2);
142+
ti = arg1;
143+
}
144+
145+
void onStack()
146+
{
147+
void* arg = ap.__stack;
148+
if (alignment > 8)
149+
arg = arg.alignUp!16;
150+
ap.__stack = alignUp(arg + size);
151+
version (BigEndian)
152+
if (size < 8)
153+
arg += 8 - size;
154+
memcpy(parmn, arg, size);
155+
}
156+
157+
// HFVA structs have already been lowered to static arrays;
158+
// lower `ti` further to the fundamental type, including HFVA
159+
// static arrays.
160+
// TODO: complex numbers
161+
if (auto ti_sarray = cast(TypeInfo_StaticArray) ti)
162+
ti = ti_sarray.value;
163+
164+
if (ti.flags() & 2)
165+
{
166+
// SIMD register(s)
167+
int offs = ap.__vr_offs;
168+
if (offs >= 0)
169+
return onStack(); // reg save area empty
170+
const usedRegSize = cast(int) ti.tsize;
171+
assert(size % usedRegSize == 0);
172+
const nreg = cast(int) (size / usedRegSize);
173+
ap.__vr_offs = offs + (nreg * 16);
174+
if (ap.__vr_offs > 0)
175+
return onStack(); // overflowed reg save area
176+
version (BigEndian)
177+
if (usedRegSize < 16)
178+
offs += 16 - usedRegSize;
179+
foreach (i; 0 .. nreg)
180+
memcpy(parmn + i * usedRegSize, ap.__vr_top + (offs + i * 16), usedRegSize);
181+
182+
return;
183+
}
184+
185+
// GP register(s)
186+
int offs = ap.__gr_offs;
187+
if (offs >= 0)
188+
return onStack(); // reg save area empty
189+
if (alignment > 8)
190+
offs = offs.alignUp!16;
191+
const nreg = cast(int) ((size + 7) / 8);
192+
ap.__gr_offs = offs + (nreg * 8);
193+
if (ap.__gr_offs > 0)
194+
return onStack(); // overflowed reg save area
195+
version (BigEndian)
196+
if (size < 8)
197+
offs += 8 - size;
198+
memcpy(parmn, ap.__gr_top + offs, size);
199+
}

src/core/internal/vararg/sysv_x64.d

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* Varargs implementation for the x86_64 System V ABI (not used for Win64).
3-
* Used by core.stdc.stdarg.
3+
* Used by core.stdc.stdarg and core.vararg.
44
*
55
* Reference: https://www.uclibc.org/docs/psABI-x86_64.pdf
66
*
@@ -20,7 +20,7 @@ version (X86_64)
2020

2121
version (SysV_x64):
2222

23-
import core.stdc.stdarg: alignUp;
23+
import core.stdc.stdarg : alignUp;
2424

2525
@system:
2626
//@nogc: // Not yet, need to make TypeInfo's member functions @nogc first
@@ -36,7 +36,7 @@ struct __va_list_tag
3636
}
3737
alias __va_list = __va_list_tag;
3838

39-
/*
39+
/**
4040
* Making it an array of 1 causes va_list to be passed as a pointer in
4141
* function argument lists
4242
*/

src/core/stdc/stdarg.d

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,15 @@ version (ARM_Any)
5757
else version (WatchOS) {}
5858
else:
5959

60-
version (ARM) version = AAPCS32;
61-
version (AArch64) version = AAPCS64;
60+
version (ARM)
61+
{
62+
version = AAPCS32;
63+
}
64+
else version (AArch64)
65+
{
66+
version = AAPCS64;
67+
static import core.internal.vararg.aarch64;
68+
}
6269
}
6370

6471

@@ -117,17 +124,7 @@ else version (AAPCS32)
117124
}
118125
else version (AAPCS64)
119126
{
120-
alias va_list = __va_list;
121-
122-
// https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst#definition-of-va-list
123-
extern (C++, std) struct __va_list
124-
{
125-
void* __stack;
126-
void* __gr_top;
127-
void* __vr_top;
128-
int __gr_offs;
129-
int __vr_offs;
130-
}
127+
alias va_list = core.internal.vararg.aarch64.va_list;
131128
}
132129
else
133130
{
@@ -217,7 +214,7 @@ T va_arg(T)(ref va_list ap)
217214
}
218215
else version (AAPCS64)
219216
{
220-
static assert(0, "Unsupported platform");
217+
return core.internal.vararg.aarch64.va_arg!T(ap);
221218
}
222219
else version (ARM_Any)
223220
{

src/core/vararg.d

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ void va_arg()(ref va_list ap, TypeInfo ti, void* parmn)
104104
}
105105
else version (AAPCS64)
106106
{
107-
static assert(0, "Unsupported platform");
107+
static import core.internal.vararg.aarch64;
108+
core.internal.vararg.aarch64.va_arg(ap, ti, parmn);
108109
}
109110
else version (ARM_Any)
110111
{

0 commit comments

Comments
 (0)