sourceextensions/gpu/lib/Gpu.xtlm

1⍝# Gpu.xtlm: the accelerate macro: a function's text handed to the GPU runner 2⍝# 3⍝# Import it with the facade: "gp:" u_se< "Gpu" brings Gpu.xtl (the 4⍝# functions) and this file (the macro) under one alias. The program 5⍝# must import the facade as gp:, since the expansion calls gp:l_ower, 6⍝# gp:b_ind, gp:r_un and gp:o_utput. 7⍝# 8⍝# u:f_ := KINDS gp:a_ccel< "{ x w -> ... }" defines a function of the same 9⍝# parameters that hands the text to the gpu extension, which lowers it 10⍝# through X_eTaL's own crates for the arguments' shapes when they are 11⍝# bound (once per set of shapes), runs it on opencl:0 with the 12⍝# arguments uploaded, and reads the result back. KINDS says how each 13⍝# argument is taken, "float" or "int" per parameter ("" for all 14⍝# Floats); an Int array must be bound as int to be looked up by. The 15⍝# function is one or two named arrays to one array, written on one 16⍝# line without quotes; its libraries are the ones the calling file 17⍝# imports (the expansion names the file, so the runner reads its u_se< 18⍝# lines). The same macro, with a runner that has load-from-source, 19⍝# bind and run, would accelerate on anything. 20 21⍝## Private helpers (text) 22 23⍝# The words of a text (split on spaces). 24ʰw̲ords ← { s → (n̲ot s = f̲irst " ") p̲artition s } 25ʰw̲ord ← { i w → d̲isclose i s̲elect w } 26 27⍝# The text as a string literal (no quotes or backslashes inside). 28ʰq̲uote ← { t → "\"" c̲at t c̲at "\"" } 29 30⍝# The second parameter's name, or "" when the function takes one. 31ʰs̲econd ← { w → 32 (3 ʰw̲ord w) m̲atch "->" ? "" 33 3 ʰw̲ord w 34} 35 36⍝# The parameter list and the bind calls, for one or two parameters 37⍝# (read from the right: the last bind happens first). 38ʰh̲ead ← { a b → 39 b m̲atch "" ? a 40 a c̲at " " c̲at b 41} 42ʰb̲inds ← { a b → 43 one ← "1 gp:b_ind " c̲at a c̲at " gp:a_fter " 44 b m̲atch "" ? one 45 "2 gp:b_ind " c̲at b c̲at " gp:a_fter " c̲at one 46} 47 48⍝## The macro 49 50⍝# KINDS gp:a_ccel< "{ x w -> body }": see the file's header. A 51⍝# function that calls a library's functions (ac:d_ense) is written in 52⍝# a file that imports that library; here, a product of primitives. 53⍝# >> "gp:" u_se< "Gpu" 54⍝# >> u:s_cores := "float float" gp:a_ccel< "{ q k -> q '+ '* i_nner 2 1 t_ranspose k }" 55⍝# >> q := 2 3 r_eshape 1.0 0.5 -1.0 0.0 2.0 0.25 56⍝# >> 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 57⍝# >> (q '+ '* i_nner 2 1 t_ranspose k) gp:n_ear q u:s_cores k 58⍝# ok 59ᵐa̲ccel< ← { kinds f → 60 (f̲irst "\"") m̲ember? f ? "bad-macro-argument right" ⎕R̲EJECT "the function's text holds a quote; write it without strings" 61 (f̲irst "\n") m̲ember? f ? "bad-macro-argument right" ⎕R̲EJECT "the function's text spans lines; write it on one" 62 w ← ʰw̲ords f 63 n̲ot (1 ʰw̲ord w) m̲atch "{" ? "bad-macro-argument right" ⎕R̲EJECT "the function must be written { x -> ... } or { x w -> ... }" 64 p1 ← 2 ʰw̲ord w 65 p2 ← ʰs̲econd w 66 spec ← (⎕F̲ILE @) c̲at "|" c̲at kinds 67 "{ " 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 " }" 68}