diff --git a/spike/backend/driver.ml b/spike/backend/driver.ml index 355a748..99deda9 100644 --- a/spike/backend/driver.ml +++ b/spike/backend/driver.ml @@ -103,6 +103,49 @@ let run src = close_out oc with Not_found -> ()); + (* ── The SysV boundary ────────────────────────────────────────────── + Three synthetic functions, built as Tast by hand rather than written in + Flan, because the surface language has no way to spell a call to an + arbitrary C symbol with eight arguments. [Tast.Rt] is the node a runtime + call already uses and the one a [declare-c] shim lands on, so this is the + real path with a made-up callee. *) + let loc = Flan.Loc.unknown in + let i64 = Flan.Types.Int Flan.Types.I64 in + let ex e = { Flan.Tast.e; ty = i64; loc } in + let lit n = ex (Flan.Tast.Int (Int64.of_int n, Flan.Types.I64)) in + let probe name params body = + { Flan.Tast.name; params; slots = Array.make (List.length params) i64; + snames = Array.make (List.length params) None; ret = i64; + body = [ body ]; fdefers = []; fparent = None; floc = loc } + in + let arg0 = ex (Flan.Tast.Local 0) in + let probes = [ + (* Eight integers: six in registers and two on the stack, which is the case + a register-only convention gets silently wrong. *) + probe "abi-8" [ i64 ] + (ex (Flan.Tast.Prim (Flan.Tast.Rt "spike_probe8", + [ arg0; lit 2; lit 3; lit 4; lit 5; lit 6; lit 7; lit 8 ]))); + (* rsp % 16 == 0 at the call. The callee does an aligned 16-byte spill and + answers -1 if it was entered misaligned. *) + probe "abi-align" [ i64 ] + (ex (Flan.Tast.Prim (Flan.Tast.Rt "spike_probe_align", [ arg0 ]))); + (* The same call, but underneath a binary operator -- so it is evaluated + with the left operand spilled on the stack. This is the one that matters: + alignment at a call site is not a property of the prologue, it is a + property of how much the expression evaluator has pushed. *) + probe "abi-align-nested" [ i64 ] + (ex (Flan.Tast.Prim (Flan.Tast.Add, + [ lit 0; + ex (Flan.Tast.Prim (Flan.Tast.Rt "spike_probe_align", [ arg0 ])) ]))); + ] in + List.iter + (fun (fd : Flan.Tast.fn) -> + let code = X86.fn ~resolve fd in + let p = jit_alloc page in + jit_write p code; jit_protect p page; + Hashtbl.replace addrs fd.Flan.Tast.name p) + probes; + print_endline "results:"; let at n = Hashtbl.find addrs n in check "spike-add 3 4" (call2 (at "spike-add") 3L 4L) 7L; @@ -112,6 +155,9 @@ let run src = check "spike-if 1 2" (call2 (at "spike-if") 1L 2L) 1L; check "spike-if 9 2" (call2 (at "spike-if") 9L 2L) 7L; check "spike-calls 5" (call1 (at "spike-calls") 5L) 656L; + check "abi-8 1" (call1 (at "abi-8") 1L) 87654321L; + check "abi-align 10" (call1 (at "abi-align") 10L) 13L; + check "abi-align-nested 10" (call1 (at "abi-align-nested") 10L) 13L; Printf.printf "\n%d checks, %d failures\n" !checks !failures; exit (if !failures = 0 then 0 else 1)