https://github.com/akkartik/mu/blob/master/apps/tests.subx
  1 # Generate code for a new function called 'run-tests' which calls in sequence
  2 # all functions starting with 'test-'.
  3 #
  4 # To build:
  5 #   $ ./subx translate 0*.subx apps/subx-common.subx apps/tests.subx  -o apps/tests
  6 
  7 == code
  8 #   instruction                     effective address                                                   register    displacement    immediate
  9 # . op          subop               mod             rm32          base        index         scale       r32
 10 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
 11 
 12 Entry:
 13     # Heap = new-segment(Heap-size)
 14     # . . push args
 15     68/push  Heap/imm32
 16     68/push  Heap-size/imm32
 17     # . . call
 18     e8/call  new-segment/disp32
 19     # . . discard args
 20     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 21     # initialize-trace-stream(256KB)
 22     # . . push args
 23     68/push  0x40000/imm32/256KB
 24     # . . call
 25     e8/call  initialize-trace-stream/disp32
 26     # . . discard args
 27     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
 28 
 29     # run tests if necessary, convert stdin if not
 30     # . prolog
 31     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 32     # initialize heap
 33     # - if argc > 1 and argv[1] == "test", then return run_tests()
 34     # . argc > 1
 35     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0/disp8         1/imm32           # compare *EBP
 36     7e/jump-if-lesser-or-equal  $run-main/disp8
 37     # . argv[1] == "test"
 38     # . . push args
 39     68/push  "test"/imm32
 40     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
 41     # . . call
 42     e8/call  kernel-string-equal?/disp32
 43     # . . discard args
 44     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 45     # . check result
 46     3d/compare-EAX-and  1/imm32
 47     75/jump-if-not-equal  $run-main/disp8
 48     # . run-tests()
 49     e8/call  run-tests/disp32
 50     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
 51     eb/jump  $main:end/disp8
 52 $run-main:
 53     # - otherwise convert stdin
 54     # convert(Stdin, Stdout)
 55     # . . push args
 56     68/push  Stdout/imm32
 57     68/push  Stdin/imm32
 58     # . . call
 59     e8/call  convert/disp32
 60     # . . discard args
 61     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 62     # . syscall(exit, 0)
 63     bb/copy-to-EBX  0/imm32
 64 $main:end:
 65     b8/copy-to-EAX  1/imm32/exit
 66     cd/syscall  0x80/imm8
 67 
 68 convert:  # in : (address buffered-file), out : (address buffered-file) -> <void>
 69     # pseudocode
 70     #   bool tests-found = false
 71     #   var line = new-stream(512, 1)
 72     #   var new-code-segment = new-stream(Segment-size, 1)
 73     #   write(new-code-segment, "\n==code\n")
 74     #   write(new-code-segment, "run-tests:\n")
 75     #   while true
 76     #     clear-stream(line)
 77     #     read-line-buffered(in, line)
 78     #     if (line->write == 0) break               # end of file
 79     #     var word-slice = next-word(line)
 80     #     if is-label?(word-slice)
 81     #       if slice-starts-with?(word-slice, "test-")
 82     #         tests-found = true
 83     #         write(new-code-segment, "  e8/call  ")
 84     #         write-slice(new-code-segment, word-slice)
 85     #         write(new-code-segment, "/disp32\n")
 86     #     rewind-stream(line)
 87     #     write-stream-data(out, line)
 88     #   if tests-found
 89     #     write(new-code-segment, "  c3/return\n")
 90     #     write-stream-data(out, new-code-segment)
 91     #   flush(out)
 92     #
 93     # . prolog
 94     55/push-EBP
 95     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 96     # . save registers
 97     50/push-EAX
 98     51/push-ECX
 99     52/push-EDX
100     53/push-EBX
101     57/push-EDI
102     # var line/ECX : (address stream byte) = stream(512)
103     81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x200/imm32       # subtract from ESP
104     68/push  0x200/imm32/length
105     68/push  0/imm32/read
106     68/push  0/imm32/write
107     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
108     # var word-slice/EDX = {0, 0}
109     68/push  0/imm32/end
110     68/push  0/imm32/start
111     89/copy                         3/mod/direct    2/rm32/EDX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDX
112     # tests-found?/EBX = false
113     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
114     # new-code-segment/EDI = new-stream(Heap, Segment-size, 1)
115     # . EAX = new-stream(Heap, Segment-size, 1)
116     # . . push args
117     68/push  1/imm32
118     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Segment-size/disp32               # push *Segment-size
119     68/push  Heap/imm32
120     # . . call
121     e8/call  new-stream/disp32
122     # . . discard args
123     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
124     # . EDI = EAX
125     89/copy                         3/mod/direct    7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy EAX to EDI
126     # write(new-code-segment, "\n== code\n")
127     # . . push args
128     68/push  "\n== code\n"/imm32
129     57/push-EDI
130     # . . call
131     e8/call  write/disp32
132     # . . discard args
133     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
134     # write(new-code-segment, "run-tests:\n")
135     # . . push args
136     68/push  "run-tests:\n"/imm32
137     57/push-EDI
138     # . . call
139     e8/call  write/disp32
140     # . . discard args
141     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
142 $convert:loop:
143     # clear-stream(line)
144     # . . push args
145     51/push-ECX
146     # . . call
147     e8/call  clear-stream/disp32
148     # . . discard args
149     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
150     # read-line-buffered(in, line)
151     # . . push args
152     51/push-ECX
153     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
154     # . . call
155     e8/call  read-line-buffered/disp32
156     # . . discard args
157     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
158 $convert:check0:
159     # if (line->write == 0) break
160     81          7/subop/compare     0/mod/indirect  1/rm32/ECX    .           .             .           .           .               0/imm32           # compare *ECX
161     0f 84/jump-if-equal  $convert:break/disp32
162     # next-word(line, word-slice)
163     # . . push args
164     52/push-EDX
165     51/push-ECX
166     # . . call
167     e8/call  next-word/disp32
168     # . . discard args
169     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
170 $convert:check-for-label:
171     # if (!is-label?(word-slice)) continue
172     # . EAX = is-label?(word-slice)
173     # . . push args
174     52/push-EDX
175     # . . call
176     e8/call  is-label?/disp32
177     # . . discard args
178     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
179     # . if (EAX == 0) continue
180     3d/compare-EAX-and  0/imm32
181     74/jump-if-equal  $convert:continue/disp8
182 $convert:check-label-prefix:
183     # strip trailing ':' from word-slice
184     ff          1/subop/decrement   1/mod/*+disp8   2/rm32/EDX    .           .             .           .           4/disp8         .                 # decrement *(EDX+4)
185     # if !slice-starts-with?(word-slice, "test-") continue
186     # . . push args
187     68/push  "test-"/imm32
188     52/push-EDX
189     # . . call
190     e8/call  slice-starts-with?/disp32
191     # . . discard args
192     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
193     # . if (EAX == 0) break
194     3d/compare-EAX-and  0/imm32
195     74/jump-if-equal  $convert:continue/disp8
196 $convert:call-test-function:
197     # tests-found? = true
198     bb/copy-to-EBX  1/imm32/true
199     # write(new-code-segment, "  e8/call  ")
200     # . . push args
201     68/push  "  e8/call  "/imm32
202     57/push-EDI
203     # . . call
204     e8/call  write/disp32
205     # . . discard args
206     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
207     # write-slice(new-code-segment, word-slice)
208     # . . push args
209     52/push-EDX
210     57/push-EDI
211     # . . call
212     e8/call  write-slice/disp32
213     # . . discard args
214     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
215     # write(new-code-segment, "/disp32\n")
216     # . . push args
217     68/push  "/disp32\n"/imm32
218     57/push-EDI
219     # . . call
220     e8/call  write/disp32
221     # . . discard args
222     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
223 $convert:continue:
224     # rewind-stream(line)
225     # . . push args
226     51/push-ECX
227     # . . call
228     e8/call  rewind-stream/disp32
229     # . . discard args
230     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
231     # write-stream-data(out, line)
232     # . . push args
233     51/push-ECX
234     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
235     # . . call
236     e8/call  write-stream-data/disp32
237     # . . discard args
238     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
239     # loop
240     e9/jump  $convert:loop/disp32
241 $convert:break:
242     # if (!tests-found?) goto end
243     81          7/subop/compare     3/mod/direct    3/rm32/EBX    .           .             .           .           .               0/imm32           # compare EBX
244     74/jump-if-equal  $convert:end/disp8
245     # write(new-code-segment, "  c3/return\n")
246     # . . push args
247     68/push  "  c3/return\n"/imm32
248     57/push-EDI
249     # . . call
250     e8/call  write/disp32
251     # . . discard args
252     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
253     # write-stream-data(out, new-code-segment)
254     # . . push args
255     57/push-EDI
256     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
257     # . . call
258     e8/call  write-stream-data/disp32
259     # . . discard args
260     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
261 $convert:end:
262     # flush(out)
263     # . . push args
264     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
265     # . . call
266     e8/call  flush/disp32
267     # . . discard args
268     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
269     # . reclaim locals
270     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x214/imm32       # add to ESP
271     # . restore registers
272     5f/pop-to-EDI
273     5b/pop-to-EBX
274     5a/pop-to-EDX
275     59/pop-to-ECX
276     58/pop-to-EAX
277     # . epilog
278     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
279     5d/pop-to-EBP
280     c3/return
281 
282 # . . vim:nowrap:textwidth=0