Skip to content

Commit ae47998

Browse files
authored
Merge pull request #4835 from rainers/rainer_winonarm
run on and build for Windows on ARM64
2 parents 3726a93 + 78eef1c commit ae47998

File tree

18 files changed

+235
-22
lines changed

18 files changed

+235
-22
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#### Platform support
1010
- Supports LLVM 15 - 19.
1111
- Initial compiler and runtime support for ppc64 and ppc64le systems that use IEEE 754R 128-bit floating-point as the default 128-bit floating-point format. (#4833)
12+
- Added support for building for Windows on ARM64. Use option '-march=arm64' to compile, 'ldc-build-runtime.exe --dFlags -march=arm64' to build the runtime libraries. (#4835)
1213

1314
#### Bug fixes
1415
- Building multi-file D applications with control-flow protection will no longer cause LDC to throw an internal compiler error. (#4828)

dmd/root/longdouble.d

+12-1
Original file line numberDiff line numberDiff line change
@@ -338,9 +338,20 @@ void ld_setll(longdouble_soft* pthis, long d)
338338

339339
void ld_setull(longdouble_soft* pthis, ulong d)
340340
{
341-
d ^= (1L << 63);
342341
version(AsmX86)
343342
{
343+
// emulator accuracy not good enough when running on Windows on ARM,
344+
// so avoid chopping off small numbers
345+
if (!(d & (1L << 63)))
346+
{
347+
asm nothrow @nogc pure @trusted
348+
{
349+
fild qword ptr d;
350+
}
351+
mixin(fstp_parg!("pthis"));
352+
return;
353+
}
354+
d ^= (1L << 63);
344355
auto pTwoPow63 = &twoPow63;
345356
mixin(fld_parg!("pTwoPow63"));
346357
asm nothrow @nogc pure @trusted

gen/abi/aarch64.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,13 @@ struct AArch64TargetABI : TargetABI {
3232
IndirectByvalRewrite indirectByvalRewrite;
3333
ArgTypesRewrite argTypesRewrite;
3434

35+
bool hasAAPCS64VaList() {
36+
return !isDarwin() &&
37+
!global.params.targetTriple->isWindowsMSVCEnvironment();
38+
}
39+
3540
bool isAAPCS64VaList(Type *t) {
36-
if (isDarwin())
41+
if (!hasAAPCS64VaList())
3742
return false;
3843

3944
// look for a __va_list struct in a `std` C++ namespace
@@ -152,7 +157,7 @@ struct AArch64TargetABI : TargetABI {
152157
}
153158

154159
Type *vaListType() override {
155-
if (isDarwin())
160+
if (!hasAAPCS64VaList())
156161
return TargetABI::vaListType(); // char*
157162

158163
// We need to pass the actual va_list type for correct mangling. Simply

gen/target.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ llvm::Type *getRealType(const llvm::Triple &triple) {
7777

7878
case Triple::aarch64:
7979
case Triple::aarch64_be:
80-
// AArch64 has 128-bit quad precision; Apple uses double
81-
return triple.isOSDarwin() ? LLType::getDoubleTy(ctx)
82-
: LLType::getFP128Ty(ctx);
80+
// AArch64 has 128-bit quad precision; Apple and MSVC use double
81+
return triple.isOSDarwin() || triple.isWindowsMSVCEnvironment()
82+
? LLType::getDoubleTy(ctx) : LLType::getFP128Ty(ctx);
8383

8484
case Triple::riscv32:
8585
case Triple::riscv64:

runtime/druntime/src/__importc_builtins.di

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,12 @@ version (LDC)
3939
}
4040
else version (ARM_Any)
4141
{
42-
// Darwin does not use __va_list
42+
// Darwin and Windows do not use __va_list
4343
version (OSX) {}
4444
else version (iOS) {}
4545
else version (TVOS) {}
4646
else version (WatchOS) {}
47+
else version (CRuntime_Microsoft) {}
4748
else:
4849

4950
version (ARM)

runtime/druntime/src/core/internal/vararg/aarch64.d

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ module core.internal.vararg.aarch64;
1414

1515
version (AArch64):
1616

17-
// Darwin uses a simpler varargs implementation
17+
// Darwin and Windows use a simpler varargs implementation
1818
version (OSX) {}
1919
else version (iOS) {}
2020
else version (TVOS) {}
2121
else version (WatchOS) {}
22+
else version (CRuntime_Microsoft) {}
2223
else:
2324

2425
import core.stdc.stdarg : alignUp;

runtime/druntime/src/core/stdc/math.d

+1-1
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ version (CRuntime_Microsoft) // fully supported since MSVCRT 12 (VS 2013) only
482482
else // for backward compatibility with older runtimes
483483
{
484484
///
485-
pure int isnan(float x) { version (Win64) return _isnanf(x); else return _isnan(cast(double) x); }
485+
pure int isnan(float x) { version (X86_64) return _isnanf(x); else return _isnan(cast(double) x); }
486486
///
487487
extern(C) pragma(mangle, "_isnan") pure int isnan(double x);
488488
///

runtime/druntime/src/core/stdc/stdarg.d

+2-1
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,12 @@ version (GNU)
5555
}
5656
else version (ARM_Any)
5757
{
58-
// Darwin uses a simpler varargs implementation
58+
// Darwin and Windows use a simpler varargs implementation
5959
version (OSX) {}
6060
else version (iOS) {}
6161
else version (TVOS) {}
6262
else version (WatchOS) {}
63+
else version (CRuntime_Microsoft) {}
6364
else:
6465

6566
version (ARM)

runtime/druntime/src/core/sys/windows/dll.d

+6-2
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ private bool isWindows8OrLater() nothrow @nogc
402402
int dll_getRefCount( HINSTANCE hInstance ) nothrow @nogc
403403
{
404404
void** peb;
405-
version (Win64)
405+
version (X86_64)
406406
{
407407
asm pure nothrow @nogc
408408
{
@@ -411,14 +411,18 @@ int dll_getRefCount( HINSTANCE hInstance ) nothrow @nogc
411411
mov peb, RAX;
412412
}
413413
}
414-
else version (Win32)
414+
else version (X86)
415415
{
416416
asm pure nothrow @nogc
417417
{
418418
mov EAX,FS:[0x30];
419419
mov peb, EAX;
420420
}
421421
}
422+
else version (AArch64)
423+
{
424+
asm nothrow @nogc { "ldr %0, [x18,%1]" : "=r" (peb) : "r" (0x30); }
425+
}
422426
dll_aux.LDR_MODULE *ldrMod = dll_aux.findLdrModule( hInstance, peb );
423427
if ( !ldrMod )
424428
return -2; // not in module list, bail out

runtime/druntime/src/core/sys/windows/stacktrace.d

+1
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ private:
230230

231231
version (X86) enum imageType = IMAGE_FILE_MACHINE_I386;
232232
else version (X86_64) enum imageType = IMAGE_FILE_MACHINE_AMD64;
233+
else version (AArch64) enum imageType = IMAGE_FILE_MACHINE_ARM64;
233234
else static assert(0, "unimplemented");
234235

235236
size_t frameNum = 0;

runtime/druntime/src/core/sys/windows/threadaux.d

+3-2
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,9 @@ struct thread_aux
167167
{
168168
static void** getTEB() nothrow @nogc @naked
169169
{
170-
version (Win32) return __asm!(void**)("mov %fs:(0x18), $0", "=r");
171-
else version (Win64) return __asm!(void**)("mov %gs:0($1), $0", "=r,r", 0x30);
170+
version (X86) return __asm!(void**)("mov %fs:(0x18), $0", "=r");
171+
else version (X86_64) return __asm!(void**)("mov %gs:0($1), $0", "=r,r", 0x30);
172+
else version (AArch64) return __asm!(void**)("mov $0, x18", "=r");
172173
else static assert(false);
173174
}
174175
}

runtime/druntime/src/core/sys/windows/winnt.d

+47-1
Original file line numberDiff line numberDiff line change
@@ -1131,7 +1131,8 @@ enum : WORD {
11311131
IMAGE_FILE_MACHINE_MIPSFPU16 = 0x0466,
11321132
IMAGE_FILE_MACHINE_EBC = 0x0EBC,
11331133
IMAGE_FILE_MACHINE_AMD64 = 0x8664,
1134-
IMAGE_FILE_MACHINE_M32R = 0x9041
1134+
IMAGE_FILE_MACHINE_M32R = 0x9041,
1135+
IMAGE_FILE_MACHINE_ARM64 = 0xAA64,
11351136
}
11361137

11371138
// ???
@@ -2257,6 +2258,51 @@ enum LEGACY_SAVE_AREA_LENGTH = XMM_SAVE_AREA32.sizeof;
22572258
DWORD64 LastExceptionFromRip;
22582259
}
22592260

2261+
} else version(AArch64) {
2262+
enum CONTEXT_ARM64 = 0x400000;
2263+
2264+
enum CONTEXT_CONTROL = (CONTEXT_ARM64 | 0x1L);
2265+
enum CONTEXT_INTEGER = (CONTEXT_ARM64 | 0x2L);
2266+
enum CONTEXT_SEGMENTS = (CONTEXT_ARM64 | 0x4L);
2267+
enum CONTEXT_FLOATING_POINT = (CONTEXT_ARM64 | 0x8L);
2268+
enum CONTEXT_DEBUG_REGISTERS = (CONTEXT_ARM64 | 0x10L);
2269+
2270+
enum CONTEXT_FULL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT);
2271+
enum CONTEXT_ALL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS);
2272+
2273+
enum ARM64_MAX_BREAKPOINTS = 8;
2274+
enum ARM64_MAX_WATCHPOINTS = 2;
2275+
2276+
union ARM64_NT_NEON128 {
2277+
struct {
2278+
ULONGLONG Low;
2279+
LONGLONG High;
2280+
};
2281+
double[2] D;
2282+
float[4] S;
2283+
WORD[8] H;
2284+
BYTE[16] B;
2285+
}
2286+
alias PARM64_NT_NEON128 = ARM64_NT_NEON128*;
2287+
2288+
align(16) struct CONTEXT
2289+
{
2290+
DWORD ContextFlags;
2291+
DWORD Cpsr;
2292+
DWORD64[31] X;
2293+
DWORD64 Sp;
2294+
DWORD64 Pc;
2295+
2296+
ARM64_NT_NEON128[32] V;
2297+
DWORD Fpcr;
2298+
2299+
DWORD Fpsr;
2300+
2301+
DWORD[ARM64_MAX_BREAKPOINTS] Bcr;
2302+
DWORD64[ARM64_MAX_BREAKPOINTS] Bvr;
2303+
DWORD[ARM64_MAX_WATCHPOINTS] Wcr;
2304+
DWORD64[ARM64_MAX_WATCHPOINTS] Wvr;
2305+
}
22602306
} else {
22612307
static assert(false, "Unsupported CPU");
22622308
// Versions for PowerPC, Alpha, SHX, and MIPS removed.

runtime/druntime/src/core/thread/fiber.d

+97
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,11 @@ private
146146
version = AsmExternal;
147147
version = AlignFiberStackTo16Byte;
148148
}
149+
else version (Windows)
150+
{
151+
version = AsmAArch64_Windows;
152+
version = AlignFiberStackTo16Byte;
153+
}
149154
}
150155
else version (ARM)
151156
{
@@ -355,6 +360,63 @@ private
355360
"~{xmm6},~{xmm7},~{xmm8},~{xmm9},~{xmm10},~{xmm11},~{xmm12},~{xmm13},~{xmm14},~{xmm15}"
356361
);
357362
}
363+
else version (AsmAArch64_Windows)
364+
{
365+
pragma(LDC_never_inline);
366+
asm pure nothrow @nogc
367+
{
368+
`// save current stack state (similar to posix version in threadasm.S)
369+
stp x19, x20, [sp, #-16]!
370+
stp x21, x22, [sp, #-16]!
371+
stp x23, x24, [sp, #-16]!
372+
stp x25, x26, [sp, #-16]!
373+
stp x27, x28, [sp, #-16]!
374+
stp fp, lr, [sp, #-16]!
375+
mov x19, sp // no need to scan FP registers, so snapshot sp here
376+
377+
stp d8, d9, [sp, #-16]!
378+
stp d10, d11, [sp, #-16]!
379+
stp d12, d13, [sp, #-16]!
380+
stp d14, d15, [sp, #-16]!
381+
382+
ldr x20, [x18, #8] // read stack range from TEB
383+
ldr x21, [x18, #16]
384+
stp x20, x21, [sp, #-16]!
385+
386+
ldr x20, [x18, #0x1478] // read Deallocation Stack
387+
ldr w21, [x18, #0x1748] // read GuaranteedStackBytes
388+
stp x20, x21, [sp, #-16]!
389+
390+
// store oldp
391+
str x19, [x0]
392+
// load newp to begin context switch
393+
sub x1, x1, #6*16
394+
mov sp, x1
395+
396+
ldp x20, x21, [sp], #16 // restore Deallocation/GuaranteedStackBytes
397+
str x20, [x18, #0x1478]
398+
str w21, [x18, #0x1748] // word only
399+
400+
ldp x20, x21, [sp], #16 // restore stack range
401+
str x20, [x18, #8]
402+
str x21, [x18, #16]
403+
404+
// load saved state from new stack
405+
ldp d14, d15, [sp], #16
406+
ldp d12, d13, [sp], #16
407+
ldp d10, d11, [sp], #16
408+
ldp d8, d9, [sp], #16
409+
410+
ldp fp, lr, [sp], #16
411+
ldp x27, x28, [sp], #16
412+
ldp x25, x26, [sp], #16
413+
ldp x23, x24, [sp], #16
414+
ldp x21, x22, [sp], #16
415+
ldp x19, x20, [sp], #16
416+
417+
ret`;
418+
}
419+
}
358420
else
359421
static assert(false);
360422
}
@@ -1616,6 +1678,41 @@ private:
16161678
push( cast(size_t) m_ctxt.bstack + m_size ); // GS:[16]
16171679
}
16181680
}
1681+
else version (AsmAArch64_Windows)
1682+
{
1683+
version (StackGrowsDown) {} else static assert( false );
1684+
1685+
push( 0x00000000_00000000 ); // another stack frame is needed
1686+
push( 0x00000000_00000000 ); // to catch exceptions in fiber_entryPoint
1687+
auto nextfp = pstack;
1688+
1689+
push( 0x00000000_00000000 ); // X20
1690+
push( 0x00000000_00000000 ); // X19
1691+
push( 0x00000000_00000000 ); // X22
1692+
push( 0x00000000_00000000 ); // X21
1693+
push( 0x00000000_00000000 ); // X24
1694+
push( 0x00000000_00000000 ); // X23
1695+
push( 0x00000000_00000000 ); // X26
1696+
push( 0x00000000_00000000 ); // X25
1697+
push( 0x00000000_00000000 ); // X28
1698+
push( 0x00000000_00000000 ); // X27
1699+
push( cast(size_t) &fiber_entryPoint ); // X30 (lr)
1700+
push( cast(size_t) nextfp ); // X29 (fp)
1701+
push( 0x00000000_00000000 ); // V9 (low)
1702+
push( 0x00000000_00000000 ); // V8 (low)
1703+
push( 0x00000000_00000000 ); // V11 (low)
1704+
push( 0x00000000_00000000 ); // V10 (low)
1705+
push( 0x00000000_00000000 ); // V13 (low)
1706+
push( 0x00000000_00000000 ); // V12 (low)
1707+
push( 0x00000000_00000000 ); // V15 (low)
1708+
push( 0x00000000_00000000 ); // V14 (low)
1709+
push( cast(size_t) m_ctxt.bstack - m_size ); // StackLimit x18[16] (X18 is TEB)
1710+
push( cast(size_t) m_ctxt.bstack ); // StackBase x18[8]
1711+
push( 0x00000000_00000000 ); // GuaranteedStackBytes
1712+
push( cast(size_t) m_ctxt.bstack - m_size ); // DeallocationStack
1713+
1714+
pstack += size_t.sizeof * 12; // exclude V8 and TEB-entries from scanning by the GC
1715+
}
16191716
else version (AsmX86_Posix)
16201717
{
16211718
push( 0x00000000 ); // Return address of fiber_entryPoint call

runtime/druntime/src/core/thread/osthread.d

+16
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,10 @@ class Thread : ThreadBase
377377
ulong[16] m_reg; // rdi,rsi,rbp,rsp,rbx,rdx,rcx,rax
378378
// r8,r9,r10,r11,r12,r13,r14,r15
379379
}
380+
else version (AArch64)
381+
{
382+
ulong[33] m_reg; // x0-x31, pc
383+
}
380384
else
381385
{
382386
static assert(false, "Architecture not supported." );
@@ -1760,6 +1764,8 @@ version (LDC_Windows)
17601764
return __asm!(void*)("mov %fs:(4), $0", "=r");
17611765
else version (X86_64)
17621766
return __asm!(void*)("mov %gs:0($1), $0", "=r,r", 8);
1767+
else version (AArch64)
1768+
return __asm!(void*)("ldr $0, [x18,$1]", "=r,r", 8);
17631769
else
17641770
static assert(false, "Architecture not supported.");
17651771
}
@@ -1918,6 +1924,16 @@ private extern (D) bool suspend( Thread t ) nothrow @nogc
19181924
t.m_reg[14] = context.R14;
19191925
t.m_reg[15] = context.R15;
19201926
}
1927+
else version (AArch64)
1928+
{
1929+
for( int i = 0; i < 31; i++ )
1930+
t.m_reg[i] = context.X[i];
1931+
1932+
t.m_reg[31] = context.Sp;
1933+
t.m_reg[32] = context.Pc;
1934+
if ( !t.m_lock )
1935+
t.m_curr.tstack = cast(void*) context.Sp;
1936+
}
19211937
else
19221938
{
19231939
static assert(false, "Architecture not supported." );

0 commit comments

Comments
 (0)