fibers B1.3b-1: x86_64 / Win64 swap_context sibling, validated on a Win7 x64 VM
The context switch is now proven on a second arch/ABI pair. A Win64 swap_context saves the complete Win64 callee-saved set: 8 GP (rbx,rbp,rdi,rsi,r12-r15) + rsp AND xmm6-xmm15 (10 XMM, 128-bit via movups -- Win64 has callee-saved XMM, unlike SysV/aarch64), plus a Win64 scribble_verify (264-byte frame, 32-byte shadow + 16-align at each call, COFF symbols, rsp-carried return address) driving the 2-fiber mutual scribble. Built --target x86_64-windows-gnu --self-contained (PE32+, output via the Win32 WriteFile boundary -- the 1660 pattern) and run on a Windows 7 x64 VM (UTM): printed '0 0 P' -- every GP + XMM callee-saved register survived the switch. Adversarially reviewed before the VM run (worker emitted the real .s and verified every call alignment, the frame offsets, the rsp/return-address round-trip, swap ordering, and COFF naming against the Win64 ABI -- no critical/minor bugs). Locked by examples/1810-concurrency-fiber-switch-win64.sx (pinned x86_64-windows-gnu, ir-only on this non-Windows host; the VM run is the runtime-correctness provenance). Good-swap-only mutual scribble (self-validating by construction; the in-process negative control was dropped to avoid an sx fn-ptr-convention issue -- detection of this exact logic was negative-controlled on aarch64 in 1808). Suite green 736/0. The B1.3 switch is proven on aarch64 + x86_64/Win64. Next: B1.4 (Io impls / M:1 scheduler).
This commit is contained in:
341
examples/1810-concurrency-fiber-switch-win64.sx
Normal file
341
examples/1810-concurrency-fiber-switch-win64.sx
Normal file
@@ -0,0 +1,341 @@
|
||||
// Win64 fiber context-switch STRESS GATE (x86_64-windows-gnu).
|
||||
// Mirrors the aarch64 §10.7 gate (examples/1808) for the Win64 ABI:
|
||||
// - callee-saved: rbx,rbp,rdi,rsi,r12-r15 (8 GP) + rsp + xmm6-xmm15 (10 XMM,
|
||||
// 128-bit — Win64 HAS callee-saved XMM, unlike SysV/aarch64).
|
||||
// - args rcx,rdx,r8,r9; result rax; 32-byte shadow + 16-align at each call;
|
||||
// COFF symbols (no leading underscore); return address rides the stack.
|
||||
// 2-fiber MUTUAL scribble: A (base 0x5000) and B (base 0x6000) each load
|
||||
// distinct sentinels into EVERY callee-saved reg and yield to each other, so a
|
||||
// sentinel survives only if swap_good saved+restored it (each fiber physically
|
||||
// clobbers the other's registers while it is suspended). Self-validating by
|
||||
// construction; the corruption-DETECTION of this exact scribble/verify logic
|
||||
// was negative-controlled on aarch64 (examples/1808). Prints three fields:
|
||||
// "<gp_mismatch> <xmm_mismatch> <P|F>" — expected "0 0 P".
|
||||
//
|
||||
// VALIDATED: built with `--target x86_64-windows-gnu --self-contained` and run
|
||||
// on a Windows 7 x64 VM (UTM) -> printed "0 0 P" (every GP + XMM callee-saved
|
||||
// survived). Pinned x86_64-windows-gnu: ir-only on a non-Windows host (the .ir
|
||||
// locks the Win64-ABI lowering); runs end-to-end on a Windows x86_64 runner.
|
||||
// Adversarially reviewed (no critical/minor bugs) before the VM run.
|
||||
|
||||
kernel32 :: #library "kernel32";
|
||||
GetStdHandle :: (n: u32) -> *void extern;
|
||||
WriteFile :: (file: *void, buf: *u8, n: u32, written: *u32, overlapped: *void) -> i32 extern;
|
||||
ExitProcess :: (code: u32) -> void extern;
|
||||
|
||||
// 30 u64: GP rbx@0 rbp@8 rdi@16 rsi@24 r12@32 r13@40 r14@48 r15@56, rsp@64,
|
||||
// pad@72, xmm6@80 xmm7@96 ... xmm15@224 (movups, 16 bytes each).
|
||||
FiberCtx :: struct { regs: [30]u64; }
|
||||
|
||||
Fiber :: struct {
|
||||
ctx: FiberCtx;
|
||||
peer: *FiberCtx;
|
||||
next: *FiberCtx;
|
||||
base: u64;
|
||||
gp: u64;
|
||||
xmm: u64;
|
||||
}
|
||||
|
||||
swap_good :: (from: *FiberCtx, to: *FiberCtx) abi(.naked) export "swap_good" {
|
||||
asm volatile {
|
||||
#string A
|
||||
movq %rbx, 0(%rcx)
|
||||
movq %rbp, 8(%rcx)
|
||||
movq %rdi, 16(%rcx)
|
||||
movq %rsi, 24(%rcx)
|
||||
movq %r12, 32(%rcx)
|
||||
movq %r13, 40(%rcx)
|
||||
movq %r14, 48(%rcx)
|
||||
movq %r15, 56(%rcx)
|
||||
movq %rsp, 64(%rcx)
|
||||
movups %xmm6, 80(%rcx)
|
||||
movups %xmm7, 96(%rcx)
|
||||
movups %xmm8, 112(%rcx)
|
||||
movups %xmm9, 128(%rcx)
|
||||
movups %xmm10, 144(%rcx)
|
||||
movups %xmm11, 160(%rcx)
|
||||
movups %xmm12, 176(%rcx)
|
||||
movups %xmm13, 192(%rcx)
|
||||
movups %xmm14, 208(%rcx)
|
||||
movups %xmm15, 224(%rcx)
|
||||
movq 0(%rdx), %rbx
|
||||
movq 8(%rdx), %rbp
|
||||
movq 16(%rdx), %rdi
|
||||
movq 24(%rdx), %rsi
|
||||
movq 32(%rdx), %r12
|
||||
movq 40(%rdx), %r13
|
||||
movq 48(%rdx), %r14
|
||||
movq 56(%rdx), %r15
|
||||
movups 80(%rdx), %xmm6
|
||||
movups 96(%rdx), %xmm7
|
||||
movups 112(%rdx), %xmm8
|
||||
movups 128(%rdx), %xmm9
|
||||
movups 144(%rdx), %xmm10
|
||||
movups 160(%rdx), %xmm11
|
||||
movups 176(%rdx), %xmm12
|
||||
movups 192(%rdx), %xmm13
|
||||
movups 208(%rdx), %xmm14
|
||||
movups 224(%rdx), %xmm15
|
||||
movq 64(%rdx), %rsp
|
||||
ret
|
||||
A
|
||||
};
|
||||
}
|
||||
|
||||
// scribble_verify(self_ctx=rcx, peer=rdx, base=r8, swapfn=r9) -> rax packed
|
||||
// (xmm_mismatch << 16) | gp_mismatch. Naked: 264-byte frame saves the caller's
|
||||
// callee-saved (it scribbles them) + base; yields via `call *%r9`; verifies on
|
||||
// resume; restores the caller regs; returns.
|
||||
scribble_verify :: (self_ctx: *FiberCtx, peer: *FiberCtx, base: u64) -> u64 abi(.naked) export "scribble_verify" {
|
||||
asm volatile {
|
||||
#string SV
|
||||
subq $264, %rsp
|
||||
movq %r8, 32(%rsp)
|
||||
movq %rbx, 40(%rsp)
|
||||
movq %rbp, 48(%rsp)
|
||||
movq %rdi, 56(%rsp)
|
||||
movq %rsi, 64(%rsp)
|
||||
movq %r12, 72(%rsp)
|
||||
movq %r13, 80(%rsp)
|
||||
movq %r14, 88(%rsp)
|
||||
movq %r15, 96(%rsp)
|
||||
movups %xmm6, 104(%rsp)
|
||||
movups %xmm7, 120(%rsp)
|
||||
movups %xmm8, 136(%rsp)
|
||||
movups %xmm9, 152(%rsp)
|
||||
movups %xmm10, 168(%rsp)
|
||||
movups %xmm11, 184(%rsp)
|
||||
movups %xmm12, 200(%rsp)
|
||||
movups %xmm13, 216(%rsp)
|
||||
movups %xmm14, 232(%rsp)
|
||||
movups %xmm15, 248(%rsp)
|
||||
leaq 1(%r8), %rbx
|
||||
leaq 2(%r8), %rbp
|
||||
leaq 3(%r8), %rdi
|
||||
leaq 4(%r8), %rsi
|
||||
leaq 5(%r8), %r12
|
||||
leaq 6(%r8), %r13
|
||||
leaq 7(%r8), %r14
|
||||
leaq 8(%r8), %r15
|
||||
leaq 9(%r8), %rax
|
||||
movq %rax, %xmm6
|
||||
leaq 10(%r8), %rax
|
||||
movq %rax, %xmm7
|
||||
leaq 11(%r8), %rax
|
||||
movq %rax, %xmm8
|
||||
leaq 12(%r8), %rax
|
||||
movq %rax, %xmm9
|
||||
leaq 13(%r8), %rax
|
||||
movq %rax, %xmm10
|
||||
leaq 14(%r8), %rax
|
||||
movq %rax, %xmm11
|
||||
leaq 15(%r8), %rax
|
||||
movq %rax, %xmm12
|
||||
leaq 16(%r8), %rax
|
||||
movq %rax, %xmm13
|
||||
leaq 17(%r8), %rax
|
||||
movq %rax, %xmm14
|
||||
leaq 18(%r8), %rax
|
||||
movq %rax, %xmm15
|
||||
call swap_good
|
||||
movq 32(%rsp), %r8
|
||||
xorq %r10, %r10
|
||||
xorq %r11, %r11
|
||||
leaq 1(%r8), %rax
|
||||
cmpq %rax, %rbx
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r10
|
||||
leaq 2(%r8), %rax
|
||||
cmpq %rax, %rbp
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r10
|
||||
leaq 3(%r8), %rax
|
||||
cmpq %rax, %rdi
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r10
|
||||
leaq 4(%r8), %rax
|
||||
cmpq %rax, %rsi
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r10
|
||||
leaq 5(%r8), %rax
|
||||
cmpq %rax, %r12
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r10
|
||||
leaq 6(%r8), %rax
|
||||
cmpq %rax, %r13
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r10
|
||||
leaq 7(%r8), %rax
|
||||
cmpq %rax, %r14
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r10
|
||||
leaq 8(%r8), %rax
|
||||
cmpq %rax, %r15
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r10
|
||||
leaq 9(%r8), %rax
|
||||
movq %xmm6, %rcx
|
||||
cmpq %rax, %rcx
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r11
|
||||
leaq 10(%r8), %rax
|
||||
movq %xmm7, %rcx
|
||||
cmpq %rax, %rcx
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r11
|
||||
leaq 11(%r8), %rax
|
||||
movq %xmm8, %rcx
|
||||
cmpq %rax, %rcx
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r11
|
||||
leaq 12(%r8), %rax
|
||||
movq %xmm9, %rcx
|
||||
cmpq %rax, %rcx
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r11
|
||||
leaq 13(%r8), %rax
|
||||
movq %xmm10, %rcx
|
||||
cmpq %rax, %rcx
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r11
|
||||
leaq 14(%r8), %rax
|
||||
movq %xmm11, %rcx
|
||||
cmpq %rax, %rcx
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r11
|
||||
leaq 15(%r8), %rax
|
||||
movq %xmm12, %rcx
|
||||
cmpq %rax, %rcx
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r11
|
||||
leaq 16(%r8), %rax
|
||||
movq %xmm13, %rcx
|
||||
cmpq %rax, %rcx
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r11
|
||||
leaq 17(%r8), %rax
|
||||
movq %xmm14, %rcx
|
||||
cmpq %rax, %rcx
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r11
|
||||
leaq 18(%r8), %rax
|
||||
movq %xmm15, %rcx
|
||||
cmpq %rax, %rcx
|
||||
setne %dl
|
||||
movzbq %dl, %rdx
|
||||
addq %rdx, %r11
|
||||
movq %r11, %rax
|
||||
shlq $16, %rax
|
||||
orq %r10, %rax
|
||||
movq 40(%rsp), %rbx
|
||||
movq 48(%rsp), %rbp
|
||||
movq 56(%rsp), %rdi
|
||||
movq 64(%rsp), %rsi
|
||||
movq 72(%rsp), %r12
|
||||
movq 80(%rsp), %r13
|
||||
movq 88(%rsp), %r14
|
||||
movq 96(%rsp), %r15
|
||||
movups 104(%rsp), %xmm6
|
||||
movups 120(%rsp), %xmm7
|
||||
movups 136(%rsp), %xmm8
|
||||
movups 152(%rsp), %xmm9
|
||||
movups 168(%rsp), %xmm10
|
||||
movups 184(%rsp), %xmm11
|
||||
movups 200(%rsp), %xmm12
|
||||
movups 216(%rsp), %xmm13
|
||||
movups 232(%rsp), %xmm14
|
||||
movups 248(%rsp), %xmm15
|
||||
addq $264, %rsp
|
||||
ret
|
||||
SV
|
||||
};
|
||||
}
|
||||
|
||||
asm {
|
||||
#string T
|
||||
.global fib_tramp
|
||||
fib_tramp:
|
||||
movq %rbx, %rcx
|
||||
subq $32, %rsp
|
||||
call fib_body
|
||||
ud2
|
||||
T,
|
||||
};
|
||||
fib_tramp :: () extern;
|
||||
|
||||
fib_body :: (self: *Fiber) export "fib_body" {
|
||||
packed := scribble_verify(@self.ctx, self.peer, self.base);
|
||||
self.gp = packed & 0xffff;
|
||||
self.xmm = (packed >> 16) & 0xffff;
|
||||
swap_good(@self.ctx, self.next);
|
||||
}
|
||||
|
||||
STACK :: 131072;
|
||||
g_out : *void = null;
|
||||
|
||||
boot :: (f: *Fiber) {
|
||||
raw : *void = VirtualAlloc(null, STACK, 0x3000, 0x4); // MEM_COMMIT|RESERVE, PAGE_READWRITE
|
||||
top : u64 = (xx raw) + STACK;
|
||||
top = top - (top % 16);
|
||||
slot : *u64 = xx (top - 8);
|
||||
slot.* = xx fib_tramp;
|
||||
i := 0;
|
||||
while i < 30 { f.ctx.regs[i] = 0; i = i + 1; }
|
||||
f.ctx.regs[0] = xx f; // rbx = self
|
||||
f.ctx.regs[8] = top - 8; // rsp
|
||||
f.gp = 0; f.xmm = 0;
|
||||
}
|
||||
|
||||
VirtualAlloc :: (addr: *void, size: i64, typ: u32, protect: u32) -> *void extern;
|
||||
|
||||
run :: () -> u64 {
|
||||
main_ctx : FiberCtx = ---;
|
||||
a : Fiber = ---; a.base = 0x5000;
|
||||
b : Fiber = ---; b.base = 0x6000;
|
||||
a.peer = @b.ctx; a.next = @b.ctx;
|
||||
b.peer = @a.ctx; b.next = @main_ctx;
|
||||
boot(@a); boot(@b);
|
||||
swap_good(@main_ctx, @a.ctx);
|
||||
// pack both fibers' counts: ((a.xmm+b.xmm) << 16) | (a.gp+b.gp)
|
||||
return (((a.xmm + b.xmm) << 16) | (a.gp + b.gp));
|
||||
}
|
||||
|
||||
emit_num :: (v: u64) {
|
||||
if v == 0 { z : [1]u8 = .[48]; w : u32 = 0; WriteFile(g_out, @z[0], 1, @w, null); return; }
|
||||
buf : [20]u8 = ---;
|
||||
i : i64 = 20;
|
||||
vv := v;
|
||||
while vv > 0 { i = i - 1; buf[i] = xx (48 + (vv % 10)); vv = vv / 10; }
|
||||
w : u32 = 0;
|
||||
WriteFile(g_out, @buf[i], xx (20 - i), @w, null);
|
||||
}
|
||||
emit_b :: (c: u8) { b : [1]u8 = ---; b[0] = c; w : u32 = 0; WriteFile(g_out, @b[0], 1, @w, null); }
|
||||
|
||||
main :: () {
|
||||
g_out = GetStdHandle(0xFFFFFFF5);
|
||||
good := run();
|
||||
gg := good & 0xffff; gx := (good >> 16) & 0xffff;
|
||||
emit_num(gg); emit_b(32); emit_num(gx); emit_b(32);
|
||||
pass := 0;
|
||||
if gg == 0 { if gx == 0 { pass = 1; } }
|
||||
if pass == 1 { emit_b(80); } else { emit_b(70); } // 'P' / 'F'
|
||||
emit_b(10);
|
||||
ExitProcess(0);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{ "target": "x86_64-windows-gnu" }
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
326
examples/expected/1810-concurrency-fiber-switch-win64.ir
Normal file
326
examples/expected/1810-concurrency-fiber-switch-win64.ir
Normal file
@@ -0,0 +1,326 @@
|
||||
|
||||
module asm ".global fib_tramp"
|
||||
module asm "fib_tramp:"
|
||||
module asm " movq %rbx, %rcx"
|
||||
module asm " subq $32, %rsp"
|
||||
module asm " call fib_body"
|
||||
module asm " ud2"
|
||||
|
||||
@g_out = internal global ptr null
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare ptr @GetStdHandle(i32) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare i32 @WriteFile(ptr, ptr, i32, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @ExitProcess(i32) #0
|
||||
|
||||
; Function Attrs: naked noinline nounwind
|
||||
define void @swap_good(ptr %0, ptr %1) #1 {
|
||||
entry:
|
||||
call void asm sideeffect " movq %rbx, 0(%rcx)\0A movq %rbp, 8(%rcx)\0A movq %rdi, 16(%rcx)\0A movq %rsi, 24(%rcx)\0A movq %rN, 32(%rcx)\0A movq %rN, 40(%rcx)\0A movq %rN, 48(%rcx)\0A movq %rN, 56(%rcx)\0A movq %rsp, 64(%rcx)\0A movups %xmmN, 80(%rcx)\0A movups %xmmN, 96(%rcx)\0A movups %xmmN, 112(%rcx)\0A movups %xmmN, 128(%rcx)\0A movups %xmmN, 144(%rcx)\0A movups %xmmN, 160(%rcx)\0A movups %xmmN, 176(%rcx)\0A movups %xmmN, 192(%rcx)\0A movups %xmmN, 208(%rcx)\0A movups %xmmN, 224(%rcx)\0A movq 0(%rdx), %rbx\0A movq 8(%rdx), %rbp\0A movq 16(%rdx), %rdi\0A movq 24(%rdx), %rsi\0A movq 32(%rdx), %rN\0A movq 40(%rdx), %rN\0A movq 48(%rdx), %rN\0A movq 56(%rdx), %rN\0A movups 80(%rdx), %xmmN\0A movups 96(%rdx), %xmmN\0A movups 112(%rdx), %xmmN\0A movups 128(%rdx), %xmmN\0A movups 144(%rdx), %xmmN\0A movups 160(%rdx), %xmmN\0A movups 176(%rdx), %xmmN\0A movups 192(%rdx), %xmmN\0A movups 208(%rdx), %xmmN\0A movups 224(%rdx), %xmmN\0A movq 64(%rdx), %rsp\0A ret\0A", ""()
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: naked noinline nounwind
|
||||
define i64 @scribble_verify(ptr %0, ptr %1, i64 %2) #1 {
|
||||
entry:
|
||||
call void asm sideeffect " subq $$264, %rsp\0A movq %rN, 32(%rsp)\0A movq %rbx, 40(%rsp)\0A movq %rbp, 48(%rsp)\0A movq %rdi, 56(%rsp)\0A movq %rsi, 64(%rsp)\0A movq %rN, 72(%rsp)\0A movq %rN, 80(%rsp)\0A movq %rN, 88(%rsp)\0A movq %rN, 96(%rsp)\0A movups %xmmN, 104(%rsp)\0A movups %xmmN, 120(%rsp)\0A movups %xmmN, 136(%rsp)\0A movups %xmmN, 152(%rsp)\0A movups %xmmN, 168(%rsp)\0A movups %xmmN, 184(%rsp)\0A movups %xmmN, 200(%rsp)\0A movups %xmmN, 216(%rsp)\0A movups %xmmN, 232(%rsp)\0A movups %xmmN, 248(%rsp)\0A leaq 1(%rN), %rbx\0A leaq 2(%rN), %rbp\0A leaq 3(%rN), %rdi\0A leaq 4(%rN), %rsi\0A leaq 5(%rN), %rN\0A leaq 6(%rN), %rN\0A leaq 7(%rN), %rN\0A leaq 8(%rN), %rN\0A leaq 9(%rN), %rax\0A movq %rax, %xmmN\0A leaq 10(%rN), %rax\0A movq %rax, %xmmN\0A leaq 11(%rN), %rax\0A movq %rax, %xmmN\0A leaq 12(%rN), %rax\0A movq %rax, %xmmN\0A leaq 13(%rN), %rax\0A movq %rax, %xmmN\0A leaq 14(%rN), %rax\0A movq %rax, %xmmN\0A leaq 15(%rN), %rax\0A movq %rax, %xmmN\0A leaq 16(%rN), %rax\0A movq %rax, %xmmN\0A leaq 17(%rN), %rax\0A movq %rax, %xmmN\0A leaq 18(%rN), %rax\0A movq %rax, %xmmN\0A call swap_good\0A movq 32(%rsp), %rN\0A xorq %rN, %rN\0A xorq %rN, %rN\0A leaq 1(%rN), %rax\0A cmpq %rax, %rbx\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 2(%rN), %rax\0A cmpq %rax, %rbp\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 3(%rN), %rax\0A cmpq %rax, %rdi\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 4(%rN), %rax\0A cmpq %rax, %rsi\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 5(%rN), %rax\0A cmpq %rax, %rN\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 6(%rN), %rax\0A cmpq %rax, %rN\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 7(%rN), %rax\0A cmpq %rax, %rN\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 8(%rN), %rax\0A cmpq %rax, %rN\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 9(%rN), %rax\0A movq %xmmN, %rcx\0A cmpq %rax, %rcx\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 10(%rN), %rax\0A movq %xmmN, %rcx\0A cmpq %rax, %rcx\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 11(%rN), %rax\0A movq %xmmN, %rcx\0A cmpq %rax, %rcx\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 12(%rN), %rax\0A movq %xmmN, %rcx\0A cmpq %rax, %rcx\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 13(%rN), %rax\0A movq %xmmN, %rcx\0A cmpq %rax, %rcx\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 14(%rN), %rax\0A movq %xmmN, %rcx\0A cmpq %rax, %rcx\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 15(%rN), %rax\0A movq %xmmN, %rcx\0A cmpq %rax, %rcx\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 16(%rN), %rax\0A movq %xmmN, %rcx\0A cmpq %rax, %rcx\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 17(%rN), %rax\0A movq %xmmN, %rcx\0A cmpq %rax, %rcx\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A leaq 18(%rN), %rax\0A movq %xmmN, %rcx\0A cmpq %rax, %rcx\0A setne %dl\0A movzbq %dl, %rdx\0A addq %rdx, %rN\0A movq %rN, %rax\0A shlq $$16, %rax\0A orq %rN, %rax\0A movq 40(%rsp), %rbx\0A movq 48(%rsp), %rbp\0A movq 56(%rsp), %rdi\0A movq 64(%rsp), %rsi\0A movq 72(%rsp), %rN\0A movq 80(%rsp), %rN\0A movq 88(%rsp), %rN\0A movq 96(%rsp), %rN\0A movups 104(%rsp), %xmmN\0A movups 120(%rsp), %xmmN\0A movups 136(%rsp), %xmmN\0A movups 152(%rsp), %xmmN\0A movups 168(%rsp), %xmmN\0A movups 184(%rsp), %xmmN\0A movups 200(%rsp), %xmmN\0A movups 216(%rsp), %xmmN\0A movups 232(%rsp), %xmmN\0A movups 248(%rsp), %xmmN\0A addq $$264, %rsp\0A ret\0A", ""()
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @fib_tramp() #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @fib_body(ptr %0) #0 {
|
||||
entry:
|
||||
%alloca = alloca ptr, align 8
|
||||
store ptr %0, ptr %alloca, align 8
|
||||
%load = load ptr, ptr %alloca, align 8
|
||||
%gep = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %load, i32 0, i32 0
|
||||
%loadN = load ptr, ptr %alloca, align 8
|
||||
%loadN = load { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %loadN, align 8
|
||||
%sg = extractvalue { { [30 x i64] }, ptr, ptr, i64, i64, i64 } %loadN, 1
|
||||
%loadN = load ptr, ptr %alloca, align 8
|
||||
%loadN = load { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %loadN, align 8
|
||||
%sgN = extractvalue { { [30 x i64] }, ptr, ptr, i64, i64, i64 } %loadN, 3
|
||||
%call = call i64 @scribble_verify(ptr %gep, ptr %sg, i64 %sgN)
|
||||
%allocaN = alloca i64, align 8
|
||||
store i64 %call, ptr %allocaN, align 8
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%and = and i64 %loadN, 65535
|
||||
%loadN = load ptr, ptr %alloca, align 8
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %loadN, i32 0, i32 4
|
||||
store i64 %and, ptr %gepN, align 8
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%lshr = lshr i64 %loadN, 16
|
||||
%andN = and i64 %lshr, 65535
|
||||
%loadN = load ptr, ptr %alloca, align 8
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %loadN, i32 0, i32 5
|
||||
store i64 %andN, ptr %gepN, align 8
|
||||
%loadN = load ptr, ptr %alloca, align 8
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %loadN, i32 0, i32 0
|
||||
%loadN = load ptr, ptr %alloca, align 8
|
||||
%loadN = load { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %loadN, align 8
|
||||
%sgN = extractvalue { { [30 x i64] }, ptr, ptr, i64, i64, i64 } %loadN, 2
|
||||
call void @swap_good(ptr %gepN, ptr %sgN)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @boot(ptr %0) #0 {
|
||||
entry:
|
||||
%alloca = alloca ptr, align 8
|
||||
store ptr %0, ptr %alloca, align 8
|
||||
%allocaN = alloca ptr, align 8
|
||||
%call = call ptr @VirtualAlloc(ptr null, i64 131072, i32 12288, i32 4)
|
||||
store ptr %call, ptr %allocaN, align 8
|
||||
%allocaN = alloca i64, align 8
|
||||
%load = load ptr, ptr %allocaN, align 8
|
||||
%pti = ptrtoint ptr %load to i64
|
||||
%add = add i64 %pti, 131072
|
||||
store i64 %add, ptr %allocaN, align 8
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%urem = urem i64 %loadN, 16
|
||||
%sub = sub i64 %loadN, %urem
|
||||
store i64 %sub, ptr %allocaN, align 8
|
||||
%allocaN = alloca ptr, align 8
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%subN = sub i64 %loadN, 8
|
||||
%itp = inttoptr i64 %subN to ptr
|
||||
store ptr %itp, ptr %allocaN, align 8
|
||||
%loadN = load ptr, ptr %allocaN, align 8
|
||||
store ptr @fib_tramp, ptr %loadN, align 8
|
||||
%allocaN = alloca i64, align 8
|
||||
store i64 0, ptr %allocaN, align 8
|
||||
br label %while.hdr.0
|
||||
|
||||
while.hdr.0: ; preds = %while.body.1, %entry
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%icmp = icmp slt i64 %loadN, 30
|
||||
br i1 %icmp, label %while.body.1, label %while.exit.2
|
||||
|
||||
while.body.1: ; preds = %while.hdr.0
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%loadN = load ptr, ptr %alloca, align 8
|
||||
%gep = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %loadN, i32 0, i32 0
|
||||
%gepN = getelementptr inbounds nuw { [30 x i64] }, ptr %gep, i32 0, i32 0
|
||||
%igp.ptr = getelementptr i64, ptr %gepN, i64 %loadN
|
||||
store i64 0, ptr %igp.ptr, align 8
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%addN = add i64 %loadN, 1
|
||||
store i64 %addN, ptr %allocaN, align 8
|
||||
br label %while.hdr.0
|
||||
|
||||
while.exit.2: ; preds = %while.hdr.0
|
||||
%loadN = load ptr, ptr %alloca, align 8
|
||||
%ptiN = ptrtoint ptr %loadN to i64
|
||||
%loadN = load ptr, ptr %alloca, align 8
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %loadN, i32 0, i32 0
|
||||
%gepN = getelementptr inbounds nuw { [30 x i64] }, ptr %gepN, i32 0, i32 0
|
||||
%igp.ptr21 = getelementptr i64, ptr %gepN, i64 0
|
||||
store i64 %ptiN, ptr %igp.ptr21, align 8
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%subN = sub i64 %loadN, 8
|
||||
%loadN = load ptr, ptr %alloca, align 8
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %loadN, i32 0, i32 0
|
||||
%gepN = getelementptr inbounds nuw { [30 x i64] }, ptr %gepN, i32 0, i32 0
|
||||
%igp.ptr27 = getelementptr i64, ptr %gepN, i64 8
|
||||
store i64 %subN, ptr %igp.ptr27, align 8
|
||||
%loadN = load ptr, ptr %alloca, align 8
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %loadN, i32 0, i32 4
|
||||
store i64 0, ptr %gepN, align 8
|
||||
%loadN = load ptr, ptr %alloca, align 8
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %loadN, i32 0, i32 5
|
||||
store i64 0, ptr %gepN, align 8
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare ptr @VirtualAlloc(ptr, i64, i32, i32) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal i64 @run() #0 {
|
||||
entry:
|
||||
%alloca = alloca { [30 x i64] }, align 8
|
||||
store { [30 x i64] } undef, ptr %alloca, align 8
|
||||
%allocaN = alloca { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, align 8
|
||||
store { { [30 x i64] }, ptr, ptr, i64, i64, i64 } undef, ptr %allocaN, align 8
|
||||
%gep = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %allocaN, i32 0, i32 3
|
||||
store i64 20480, ptr %gep, align 8
|
||||
%allocaN = alloca { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, align 8
|
||||
store { { [30 x i64] }, ptr, ptr, i64, i64, i64 } undef, ptr %allocaN, align 8
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %allocaN, i32 0, i32 3
|
||||
store i64 24576, ptr %gepN, align 8
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %allocaN, i32 0, i32 0
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %allocaN, i32 0, i32 1
|
||||
store ptr %gepN, ptr %gepN, align 8
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %allocaN, i32 0, i32 0
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %allocaN, i32 0, i32 2
|
||||
store ptr %gepN, ptr %gepN, align 8
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %allocaN, i32 0, i32 0
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %allocaN, i32 0, i32 1
|
||||
store ptr %gepN, ptr %gepN, align 8
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %allocaN, i32 0, i32 2
|
||||
store ptr %alloca, ptr %gepN, align 8
|
||||
call void @boot(ptr %allocaN)
|
||||
call void @boot(ptr %allocaN)
|
||||
%gepN = getelementptr inbounds nuw { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %allocaN, i32 0, i32 0
|
||||
call void @swap_good(ptr %alloca, ptr %gepN)
|
||||
%load = load { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %allocaN, align 8
|
||||
%sg = extractvalue { { [30 x i64] }, ptr, ptr, i64, i64, i64 } %load, 5
|
||||
%loadN = load { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %allocaN, align 8
|
||||
%sgN = extractvalue { { [30 x i64] }, ptr, ptr, i64, i64, i64 } %loadN, 5
|
||||
%add = add i64 %sg, %sgN
|
||||
%shl = shl i64 %add, 16
|
||||
%loadN = load { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %allocaN, align 8
|
||||
%sgN = extractvalue { { [30 x i64] }, ptr, ptr, i64, i64, i64 } %loadN, 4
|
||||
%loadN = load { { [30 x i64] }, ptr, ptr, i64, i64, i64 }, ptr %allocaN, align 8
|
||||
%sgN = extractvalue { { [30 x i64] }, ptr, ptr, i64, i64, i64 } %loadN, 4
|
||||
%addN = add i64 %sgN, %sgN
|
||||
%or = or i64 %shl, %addN
|
||||
ret i64 %or
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @emit_num(i64 %0) #0 {
|
||||
entry:
|
||||
%alloca = alloca i64, align 8
|
||||
%allocaN = alloca [1 x i8], align 1
|
||||
%allocaN = alloca i32, align 4
|
||||
%allocaN = alloca [20 x i8], align 1
|
||||
%allocaN = alloca i64, align 8
|
||||
%allocaN = alloca i64, align 8
|
||||
%allocaN = alloca i32, align 4
|
||||
store i64 %0, ptr %alloca, align 8
|
||||
%load = load i64, ptr %alloca, align 8
|
||||
%icmp = icmp eq i64 %load, 0
|
||||
br i1 %icmp, label %if.then.3, label %if.merge.4
|
||||
|
||||
if.then.3: ; preds = %entry
|
||||
store [1 x i8] c"0", ptr %allocaN, align 1
|
||||
store i32 0, ptr %allocaN, align 4
|
||||
%gload = load ptr, ptr @g_out, align 8
|
||||
%igp.ptr = getelementptr i8, ptr %allocaN, i64 0
|
||||
%call = call i32 @WriteFile(ptr %gload, ptr %igp.ptr, i32 1, ptr %allocaN, ptr null)
|
||||
ret void
|
||||
|
||||
if.merge.4: ; preds = %entry
|
||||
store i64 20, ptr %allocaN, align 8
|
||||
%loadN = load i64, ptr %alloca, align 8
|
||||
store i64 %loadN, ptr %allocaN, align 8
|
||||
br label %while.hdr.5
|
||||
|
||||
while.hdr.5: ; preds = %while.body.6, %if.merge.4
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%icmpN = icmp ugt i64 %loadN, 0
|
||||
br i1 %icmpN, label %while.body.6, label %while.exit.7
|
||||
|
||||
while.body.6: ; preds = %while.hdr.5
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%sub = sub i64 %loadN, 1
|
||||
store i64 %sub, ptr %allocaN, align 8
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%urem = urem i64 %loadN, 10
|
||||
%add = add i64 48, %urem
|
||||
%trunc = trunc i64 %add to i8
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%igp.ptr12 = getelementptr i8, ptr %allocaN, i64 %loadN
|
||||
store i8 %trunc, ptr %igp.ptr12, align 1
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%udiv = udiv i64 %loadN, 10
|
||||
store i64 %udiv, ptr %allocaN, align 8
|
||||
br label %while.hdr.5
|
||||
|
||||
while.exit.7: ; preds = %while.hdr.5
|
||||
store i32 0, ptr %allocaN, align 4
|
||||
%gloadN = load ptr, ptr @g_out, align 8
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%igp.ptr17 = getelementptr i8, ptr %allocaN, i64 %loadN
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%subN = sub i64 20, %loadN
|
||||
%truncN = trunc i64 %subN to i32
|
||||
%callN = call i32 @WriteFile(ptr %gloadN, ptr %igp.ptr17, i32 %truncN, ptr %allocaN, ptr null)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @emit_b(i8 %0) #0 {
|
||||
entry:
|
||||
%alloca = alloca i8, align 1
|
||||
store i8 %0, ptr %alloca, align 1
|
||||
%allocaN = alloca [1 x i8], align 1
|
||||
%load = load i8, ptr %alloca, align 1
|
||||
%igp.ptr = getelementptr i8, ptr %allocaN, i64 0
|
||||
store i8 %load, ptr %igp.ptr, align 1
|
||||
%allocaN = alloca i32, align 4
|
||||
store i32 0, ptr %allocaN, align 4
|
||||
%gload = load ptr, ptr @g_out, align 8
|
||||
%igp.ptr3 = getelementptr i8, ptr %allocaN, i64 0
|
||||
%call = call i32 @WriteFile(ptr %gload, ptr %igp.ptr3, i32 1, ptr %allocaN, ptr null)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define i32 @main() #0 {
|
||||
entry:
|
||||
%call = call ptr @GetStdHandle(i32 -11)
|
||||
store ptr %call, ptr @g_out, align 8
|
||||
%callN = call i64 @run()
|
||||
%alloca = alloca i64, align 8
|
||||
store i64 %callN, ptr %alloca, align 8
|
||||
%load = load i64, ptr %alloca, align 8
|
||||
%and = and i64 %load, 65535
|
||||
%allocaN = alloca i64, align 8
|
||||
store i64 %and, ptr %allocaN, align 8
|
||||
%loadN = load i64, ptr %alloca, align 8
|
||||
%lshr = lshr i64 %loadN, 16
|
||||
%andN = and i64 %lshr, 65535
|
||||
%allocaN = alloca i64, align 8
|
||||
store i64 %andN, ptr %allocaN, align 8
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
call void @emit_num(i64 %loadN)
|
||||
call void @emit_b(i8 32)
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
call void @emit_num(i64 %loadN)
|
||||
call void @emit_b(i8 32)
|
||||
%allocaN = alloca i64, align 8
|
||||
store i64 0, ptr %allocaN, align 8
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%icmp = icmp eq i64 %loadN, 0
|
||||
br i1 %icmp, label %if.then.8, label %if.merge.9
|
||||
|
||||
if.then.8: ; preds = %entry
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%icmpN = icmp eq i64 %loadN, 0
|
||||
br i1 %icmpN, label %if.then.10, label %if.merge.11
|
||||
|
||||
if.merge.9: ; preds = %if.merge.11, %entry
|
||||
%loadN = load i64, ptr %allocaN, align 8
|
||||
%icmpN = icmp eq i64 %loadN, 1
|
||||
br i1 %icmpN, label %if.then.12, label %if.else.13
|
||||
|
||||
if.then.10: ; preds = %if.then.8
|
||||
store i64 1, ptr %allocaN, align 8
|
||||
br label %if.merge.11
|
||||
|
||||
if.merge.11: ; preds = %if.then.10, %if.then.8
|
||||
br label %if.merge.9
|
||||
|
||||
if.then.12: ; preds = %if.merge.9
|
||||
call void @emit_b(i8 80)
|
||||
br label %if.merge.14
|
||||
|
||||
if.else.13: ; preds = %if.merge.9
|
||||
call void @emit_b(i8 70)
|
||||
br label %if.merge.14
|
||||
|
||||
if.merge.14: ; preds = %if.else.13, %if.then.12
|
||||
call void @emit_b(i8 10)
|
||||
call void @ExitProcess(i32 0)
|
||||
ret i32 0
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
Reference in New Issue
Block a user