Skip to content

Commit 26ddb90

Browse files
committed
Support Cygwin 64 bits
- Add support for the Win64 ABI to the x86_64 port - Update vararg support to handle Win64 conventions - Configure support for x86_64-cygwin64
1 parent e9c738e commit 26ddb90

File tree

17 files changed

+415
-118
lines changed

17 files changed

+415
-118
lines changed

configure

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ Supported targets:
5454
x86_64-linux (x86 64 bits, Linux)
5555
x86_64-bsd (x86 64 bits, BSD)
5656
x86_64-macosx (x86 64 bits, MacOS X)
57+
x86_64-cygwin (x86 64 bits, Cygwin environment under Windows)
5758
rv32-linux (RISC-V 32 bits, Linux)
5859
rv64-linux (RISC-V 64 bits, Linux)
5960
aarch64-linux (AArch64, i.e. ARMv8 in 64-bit mode, Linux)
@@ -387,6 +388,18 @@ if test "$arch" = "x86" -a "$bitsize" = "64"; then
387388
libmath=""
388389
system="macosx"
389390
;;
391+
cygwin)
392+
abi="standard"
393+
casm="${toolprefix}gcc"
394+
casm_options="-m64 -c"
395+
cc="${toolprefix}gcc -m64"
396+
clinker="${toolprefix}gcc"
397+
clinker_options="-m64"
398+
cprepro="${toolprefix}gcc"
399+
cprepro_options="-std=c99 -m64 -U__GNUC__ '-D__attribute__(x)=' -E"
400+
libmath="-lm"
401+
system="cygwin"
402+
;;
390403
*)
391404
echo "Error: invalid eabi/system '$target' for architecture X86_64." 1>&2
392405
echo "$usage" 1>&2

runtime/x86_64/i64_dtou.S

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@
3939
// Conversion float -> unsigned long
4040

4141
FUNCTION(__compcert_i64_dtou)
42-
ucomisd .LC1(%rip), %xmm0
42+
ucomisd .LC1(%rip), FP_ARG_1
4343
jnb 1f
44-
cvttsd2siq %xmm0, %rax
44+
cvttsd2siq FP_ARG_1, INT_RES
4545
ret
46-
1: subsd .LC1(%rip), %xmm0
47-
cvttsd2siq %xmm0, %rax
48-
addq .LC2(%rip), %rax
46+
1: subsd .LC1(%rip), FP_ARG_1
47+
cvttsd2siq FP_ARG_1, INT_RES
48+
addq .LC2(%rip), INT_RES
4949
ret
5050

5151
.p2align 3

runtime/x86_64/i64_utod.S

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,18 @@
3939
// Conversion unsigned long -> double-precision float
4040

4141
FUNCTION(__compcert_i64_utod)
42-
testq %rdi, %rdi
42+
testq INT_ARG_1, INT_ARG_1
4343
js 1f
44-
pxor %xmm0, %xmm0 // if < 2^63,
45-
cvtsi2sdq %rdi, %xmm0 // convert as if signed
44+
pxor FP_RES, FP_RES // if < 2^63,
45+
cvtsi2sdq INT_ARG_1, FP_RES // convert as if signed
4646
ret
4747
1: // if >= 2^63, use round-to-odd trick
48-
movq %rdi, %rax
48+
movq INT_ARG_1, %rax
4949
shrq %rax
50-
andq $1, %rdi
51-
orq %rdi, %rax // (arg >> 1) | (arg & 1)
52-
pxor %xmm0, %xmm0
53-
cvtsi2sdq %rax, %xmm0 // convert as if signed
54-
addsd %xmm0, %xmm0 // multiply result by 2.0
50+
andq $1, INT_ARG_1
51+
orq INT_ARG_1, %rax // (arg >> 1) | (arg & 1)
52+
pxor FP_RES, FP_RES
53+
cvtsi2sdq %rax, FP_RES // convert as if signed
54+
addsd FP_RES, FP_RES // multiply result by 2.0
5555
ret
5656
ENDFUNCTION(__compcert_i64_utod)

runtime/x86_64/i64_utof.S

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,18 @@
3939
// Conversion unsigned long -> single-precision float
4040

4141
FUNCTION(__compcert_i64_utof)
42-
testq %rdi, %rdi
42+
testq INT_ARG_1, INT_ARG_1
4343
js 1f
44-
pxor %xmm0, %xmm0 // if < 2^63,
45-
cvtsi2ssq %rdi, %xmm0 // convert as if signed
44+
pxor FP_RES, FP_RES // if < 2^63,
45+
cvtsi2ssq INT_ARG_1, FP_RES // convert as if signed
4646
ret
4747
1: // if >= 2^63, use round-to-odd trick
48-
movq %rdi, %rax
48+
movq INT_ARG_1, %rax
4949
shrq %rax
50-
andq $1, %rdi
51-
orq %rdi, %rax // (arg >> 1) | (arg & 1)
52-
pxor %xmm0, %xmm0
53-
cvtsi2ssq %rax, %xmm0 // convert as if signed
54-
addss %xmm0, %xmm0 // multiply result by 2.0
50+
andq $1, INT_ARG_1
51+
orq INT_ARG_1, %rax // (arg >> 1) | (arg & 1)
52+
pxor FP_RES, FP_RES
53+
cvtsi2ssq %rax, FP_RES // convert as if signed
54+
addss FP_RES, FP_RES // multiply result by 2.0
5555
ret
5656
ENDFUNCTION(__compcert_i64_utof)

runtime/x86_64/sysdeps.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,25 @@ _##f:
6363

6464
#if defined(SYS_cygwin)
6565

66-
#define GLOB(x) _##x
66+
#define GLOB(x) x
6767
#define FUNCTION(f) \
6868
.text; \
69-
.globl _##f; \
69+
.globl f; \
7070
.align 16; \
71-
_##f:
71+
f:
7272

7373
#define ENDFUNCTION(f)
7474

7575
#endif
76+
77+
// Names for argument and result registers
78+
79+
#if defined(SYS_cygwin)
80+
#define INT_ARG_1 %rcx
81+
#else
82+
#define INT_ARG_1 %rdi
83+
#endif
84+
#define FP_ARG_1 %xmm0
85+
#define INT_RES %rax
86+
#define FP_RES %xmm0
87+

runtime/x86_64/vararg.S

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@
3434

3535
// Helper functions for variadic functions <stdarg.h>. x86_64 version.
3636

37+
#include "sysdeps.h"
38+
39+
// ELF ABI
40+
41+
#if defined(SYS_linux) || defined(SYS_bsd) || defined(SYS_macosx)
42+
3743
// typedef struct {
3844
// unsigned int gp_offset;
3945
// unsigned int fp_offset;
@@ -60,8 +66,6 @@
6066
// unsigned long long __compcert_va_int64(va_list ap);
6167
// double __compcert_va_float64(va_list ap);
6268

63-
#include "sysdeps.h"
64-
6569
FUNCTION(__compcert_va_int32)
6670
movl 0(%rdi), %edx // edx = gp_offset
6771
cmpl $48, %edx
@@ -146,3 +150,58 @@ FUNCTION(__compcert_va_saveregs)
146150
movaps %xmm7, 160(%r10)
147151
1: ret
148152
ENDFUNCTION(__compcert_va_saveregs)
153+
154+
#endif
155+
156+
// Windows ABI
157+
158+
#if defined(SYS_cygwin)
159+
160+
// typedef void * va_list;
161+
// unsigned int __compcert_va_int32(va_list * ap);
162+
// unsigned long long __compcert_va_int64(va_list * ap);
163+
// double __compcert_va_float64(va_list * ap);
164+
165+
FUNCTION(__compcert_va_int32) // %rcx = pointer to argument pointer
166+
movq 0(%rcx), %rdx // %rdx = current argument pointer
167+
movl 0(%rdx), %eax // load the int32 value there
168+
addq $8, %rdx // increment argument pointer by 8
169+
movq %rdx, 0(%rcx)
170+
ret
171+
ENDFUNCTION(__compcert_va_int32)
172+
173+
FUNCTION(__compcert_va_int64) // %rcx = pointer to argument pointer
174+
movq 0(%rcx), %rdx // %rdx = current argument pointer
175+
movq 0(%rdx), %rax // load the int64 value there
176+
addq $8, %rdx // increment argument pointer by 8
177+
movq %rdx, 0(%rcx)
178+
ret
179+
ENDFUNCTION(__compcert_va_int64)
180+
181+
FUNCTION(__compcert_va_float64) // %rcx = pointer to argument pointer
182+
movq 0(%rcx), %rdx // %rdx = current argument pointer
183+
movsd 0(%rdx), %xmm0 // load the float64 value there
184+
addq $8, %rdx // increment argument pointer by 8
185+
movq %rdx, 0(%rcx)
186+
ret
187+
ENDFUNCTION(__compcert_va_float64)
188+
189+
FUNCTION(__compcert_va_composite)
190+
jmp GLOB(__compcert_va_int64) // by-ref convention, FIXME
191+
ENDFUNCTION(__compcert_va_composite)
192+
193+
// Save arguments passed in register in the stack at beginning of vararg
194+
// function. The caller of the vararg function reserved 32 bytes of stack
195+
// just for this purpose.
196+
// FP arguments are passed both in FP registers and integer registers,
197+
// so it's enough to save the integer registers used for parameter passing.
198+
199+
FUNCTION(__compcert_va_saveregs)
200+
movq %rcx, 16(%rsp)
201+
movq %rdx, 24(%rsp)
202+
movq %r8, 32(%rsp)
203+
movq %r9, 40(%rsp)
204+
ret
205+
ENDFUNCTION(__compcert_va_saveregs)
206+
207+
#endif

x86/Asm.v

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ Inductive instruction: Type :=
279279
| Pmaxsd (rd: freg) (r2: freg)
280280
| Pminsd (rd: freg) (r2: freg)
281281
| Pmovb_rm (rd: ireg) (a: addrmode)
282+
| Pmovq_rf (rd: ireg) (r1: freg)
282283
| Pmovsq_mr (a: addrmode) (rs: freg)
283284
| Pmovsq_rm (rd: freg) (a: addrmode)
284285
| Pmovsb
@@ -998,6 +999,7 @@ Definition exec_instr (f: function) (i: instruction) (rs: regset) (m: mem) : out
998999
| Pmaxsd _ _
9991000
| Pminsd _ _
10001001
| Pmovb_rm _ _
1002+
| Pmovq_rf _ _
10011003
| Pmovsq_rm _ _
10021004
| Pmovsq_mr _ _
10031005
| Pmovsb

x86/Asmexpand.ml

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ let stack_alignment () = 16
4444
let _Plea (r, addr) =
4545
if Archi.ptr64 then Pleaq (r, addr) else Pleal (r, addr)
4646

47-
(* SP adjustment to allocate or free a stack frame *)
47+
(* SP adjustment to allocate or free a stack frame. *)
4848

4949
let align n a =
5050
if n >= 0 then (n + a - 1) land (-a) else n land (-a)
@@ -56,7 +56,7 @@ let sp_adjustment_32 sz =
5656
(* The top 4 bytes have already been allocated by the "call" instruction. *)
5757
sz - 4
5858

59-
let sp_adjustment_64 sz =
59+
let sp_adjustment_elf64 sz =
6060
let sz = Z.to_int sz in
6161
if is_current_function_variadic() then begin
6262
(* If variadic, add room for register save area, which must be 16-aligned *)
@@ -73,6 +73,13 @@ let sp_adjustment_64 sz =
7373
(sz - 8, -1)
7474
end
7575

76+
let sp_adjustment_win64 sz =
77+
let sz = Z.to_int sz in
78+
(* Preserve proper alignment of the stack *)
79+
let sz = align sz 16 in
80+
(* The top 8 bytes have already been allocated by the "call" instruction. *)
81+
sz - 8
82+
7683
(* Built-ins. They come in two flavors:
7784
- annotation statements: take their arguments in registers or stack
7885
locations; generate no code;
@@ -256,7 +263,7 @@ let expand_builtin_va_start_32 r =
256263
emit (Pleal (RAX, linear_addr RSP (Z.of_uint32 ofs)));
257264
emit (Pmovl_mr (linear_addr r _0z, RAX))
258265

259-
let expand_builtin_va_start_64 r =
266+
let expand_builtin_va_start_elf64 r =
260267
if not (is_current_function_variadic ()) then
261268
invalid_arg "Fatal error: va_start used in non-vararg function";
262269
let (ir, fr, ofs) =
@@ -287,6 +294,17 @@ let expand_builtin_va_start_64 r =
287294
emit (Pleaq (RAX, linear_addr RSP (Z.of_uint64 reg_save_area)));
288295
emit (Pmovq_mr (linear_addr r _16z, RAX))
289296

297+
let expand_builtin_va_start_win64 r =
298+
if not (is_current_function_variadic ()) then
299+
invalid_arg "Fatal error: va_start used in non-vararg function";
300+
let num_args =
301+
List.length (get_current_function_args()) in
302+
let ofs =
303+
Int64.(add !current_function_stacksize
304+
(mul 8L (of_int num_args))) in
305+
emit (Pleaq (RAX, linear_addr RSP (Z.of_uint64 ofs)));
306+
emit (Pmovq_mr (linear_addr r _0z, RAX))
307+
290308
(* FMA operations *)
291309

292310
(* vfmadd<i><j><k> r1, r2, r3 performs r1 := ri * rj + rk
@@ -463,8 +481,8 @@ let expand_builtin_inline name args res =
463481
(* Vararg stuff *)
464482
| "__builtin_va_start", [BA(IR a)], _ ->
465483
assert (a = RDX);
466-
if Archi.ptr64
467-
then expand_builtin_va_start_64 a
484+
if Archi.win64 then expand_builtin_va_start_win64 a
485+
else if Archi.ptr64 then expand_builtin_va_start_elf64 a
468486
else expand_builtin_va_start_32 a
469487
(* Synchronization *)
470488
| "__builtin_membar", [], _ ->
@@ -476,24 +494,66 @@ let expand_builtin_inline name args res =
476494
| _ ->
477495
raise (Error ("unrecognized builtin " ^ name))
478496

479-
(* Calls to variadic functions for x86-64: register AL must contain
497+
(* Calls to variadic functions for x86-64 ELF: register AL must contain
480498
the number of XMM registers used for parameter passing. To be on
481-
the safe side. do the same if the called function is
499+
the safe side, do the same if the called function is
482500
unprototyped. *)
483501

484-
let set_al sg =
485-
if Archi.ptr64 && (sg.sig_cc.cc_vararg || sg.sig_cc.cc_unproto) then begin
502+
let fixup_funcall_elf64 sg =
503+
if sg.sig_cc.cc_vararg || sg.sig_cc.cc_unproto then begin
486504
let (ir, fr, ofs) = next_arg_locations 0 0 0 sg.sig_args in
487505
emit (Pmovl_ri (RAX, coqint_of_camlint (Int32.of_int fr)))
488506
end
489507

508+
(* Calls to variadic functions for x86-64 Windows:
509+
FP arguments passed in FP registers must also be passed in integer
510+
registers.
511+
*)
512+
513+
let rec copy_fregs_to_iregs args fr ir =
514+
match (ir, fr, args) with
515+
| (i1 :: ir, f1 :: fr, (Tfloat | Tsingle) :: args) ->
516+
emit (Pmovq_rf (i1, f1));
517+
copy_fregs_to_iregs args fr ir
518+
| (i1 :: ir, f1 :: fr, _ :: args) ->
519+
copy_fregs_to_iregs args fr ir
520+
| _ ->
521+
()
522+
523+
let fixup_funcall_win64 sg =
524+
if sg.sig_cc.cc_vararg then
525+
copy_fregs_to_iregs sg.sig_args [XMM0; XMM1; XMM2; XMM3] [RCX; RDX; R8; R9]
526+
527+
let fixup_funcall sg =
528+
if Archi.ptr64
529+
then if Archi.win64
530+
then fixup_funcall_win64 sg
531+
else fixup_funcall_elf64 sg
532+
else ()
533+
490534
(* Expansion of instructions *)
491535

492536
let expand_instruction instr =
493537
match instr with
494538
| Pallocframe (sz, ofs_ra, ofs_link) ->
495-
if Archi.ptr64 then begin
496-
let (sz, save_regs) = sp_adjustment_64 sz in
539+
if Archi.win64 then begin
540+
let sz = sp_adjustment_win64 sz in
541+
if is_current_function_variadic() then
542+
(* Save parameters passed in registers in reserved stack area *)
543+
emit (Pcall_s (intern_string "__compcert_va_saveregs",
544+
{sig_args = []; sig_res = Tvoid; sig_cc = cc_default}));
545+
(* Allocate frame *)
546+
let sz' = Z.of_uint sz in
547+
emit (Psubl_ri (RSP, sz'));
548+
emit (Pcfi_adjust sz');
549+
(* Stack chaining *)
550+
let addr1 = linear_addr RSP (Z.of_uint (sz + 8)) in
551+
let addr2 = linear_addr RSP ofs_link in
552+
emit (Pleaq (RAX,addr1));
553+
emit (Pmovq_mr (addr2, RAX));
554+
current_function_stacksize := Int64.of_int (sz + 8)
555+
end else if Archi.ptr64 then begin
556+
let (sz, save_regs) = sp_adjustment_elf64 sz in
497557
(* Allocate frame *)
498558
let sz' = Z.of_uint sz in
499559
emit (Psubq_ri (RSP, sz'));
@@ -525,15 +585,18 @@ let expand_instruction instr =
525585
PrintAsmaux.current_function_stacksize := Int32.of_int sz
526586
end
527587
| Pfreeframe(sz, ofs_ra, ofs_link) ->
528-
if Archi.ptr64 then begin
529-
let (sz, _) = sp_adjustment_64 sz in
588+
if Archi.win64 then begin
589+
let sz = sp_adjustment_win64 sz in
590+
emit (Paddq_ri (RSP, Z.of_uint sz))
591+
end else if Archi.ptr64 then begin
592+
let (sz, _) = sp_adjustment_elf64 sz in
530593
emit (Paddq_ri (RSP, Z.of_uint sz))
531594
end else begin
532595
let sz = sp_adjustment_32 sz in
533596
emit (Paddl_ri (RSP, Z.of_uint sz))
534597
end
535598
| Pjmp_s(_, sg) | Pjmp_r(_, sg) | Pcall_s(_, sg) | Pcall_r(_, sg) ->
536-
set_al sg;
599+
fixup_funcall sg;
537600
emit instr
538601
| Pbuiltin (ef,args, res) ->
539602
begin

0 commit comments

Comments
 (0)