macro libraryextensions/gpu/lib/Gpu.xtlm
Gpu.xtlm: the accelerate macro: a function's text handed to the GPU runner
Import it with the facade: "gp:" u_se< "Gpu" brings Gpu.xtl (the functions) and this file (the macro) under one alias. The program must import the facade as gp:, since the expansion calls gp:l_ower, gp:b_ind, gp:r_un and gp:o_utput.
u:f_ := KINDS gp:a_ccel< "{ x w -> ... }" defines a function of the same parameters that hands the text to the gpu extension, which lowers it through X_eTaL's own crates for the arguments' shapes when they are bound (once per set of shapes), runs it on opencl:0 with the arguments uploaded, and reads the result back. KINDS says how each argument is taken, "float" or "int" per parameter ("" for all Floats); an Int array must be bound as int to be looked up by. The function is one or two named arrays to one array, written on one line without quotes; its libraries are the ones the calling file imports (the expansion names the file, so the runner reads its u_se< lines). The same macro, with a runner that has load-from-source, bind and run, would accelerate on anything.
Private helpers (text)
ʰw̲ords : Char -> Box Char
The words of a text (split on spaces).
ʰw̲ords ← { s → (n̲ot s = f̲irst " ") p̲artition s }
ʰq̲uote : Char -> Char
The text as a string literal (no quotes or backslashes inside).
ʰq̲uote ← { t → "\"" c̲at t c̲at "\"" }
ʰs̲econd : Box Char -> Char
The second parameter's name, or "" when the function takes one.
ʰs̲econd ← { w → (3 ʰw̲ord w) m̲atch "->" ? "" 3 ʰw̲ord w }
ʰh̲ead : Char -> Char -> Char
The parameter list and the bind calls, for one or two parameters (read from the right: the last bind happens first).
ʰh̲ead ← { a b → b m̲atch "" ? a a c̲at " " c̲at b }
ʰb̲inds : Char -> Char -> Char
ʰb̲inds ← { a b → one ← "1 gp:b_ind " c̲at a c̲at " gp:a_fter " b m̲atch "" ? one "2 gp:b_ind " c̲at b c̲at " gp:a_fter " c̲at one }
The macro
ᵐa̲ccel< : Char -> Char -> Char
KINDS gp:a_ccel< "{ x w -> body }": see the file's header. A function that calls a library's functions (ac:d_ense) is written in a file that imports that library; here, a product of primitives.
ᵍᵖ⁼u̲se< "Gpu"
ᵘs̲cores ← "float float" ᵍᵖa̲ccel< "{ q k -> q '+ '* i_nner 2 1 t_ranspose k }"
q ← 2 3 r̲eshape 1.0 0.5 -1.0 0.0 2.0 0.25
k ← 4 3 r̲eshape 0.5 1.0 0.0 -1.0 0.5 2.0 1.5 -0.5 1.0 0.0 0.0 1.0
(q '+ '× i̲nner 2 1 t̲ranspose k) ᵍᵖn̲ear q ᵘs̲cores k ok
ᵐa̲ccel< ← { kinds f → (f̲irst "\"") m̲ember? f ? "bad-macro-argument right" ⎕R̲EJECT "the function's text holds a quote; write it without strings" (f̲irst "\n") m̲ember? f ? "bad-macro-argument right" ⎕R̲EJECT "the function's text spans lines; write it on one" w ← ʰw̲ords f n̲ot (1 ʰw̲ord w) m̲atch "{" ? "bad-macro-argument right" ⎕R̲EJECT "the function must be written { x -> ... } or { x w -> ... }" p1 ← 2 ʰw̲ord w p2 ← ʰs̲econd w spec ← (⎕F̲ILE @) c̲at "|" c̲at kinds "{ " c̲at (p1 ʰh̲ead p2) c̲at " -> gp:o_utput 1 gp:a_fter gp:r_un 0 gp:a_fter " c̲at (p1 ʰb̲inds p2) c̲at (ʰq̲uote f) c̲at " gp:l_ower " c̲at (ʰq̲uote spec) c̲at " }" }