.
[mu.git] / 301array-equal.subx
blobfd46ccb64a8221b97f780350ad692389612992fb
1 # Comparing arrays of numbers.
3 == code
5 array-equal?:  # a: (addr array int), b: (addr array int) -> result/eax: boolean
6     # pseudocode:
7     #   asize = a->size
8     #   if (asize != b->size) return false
9     #   i = 0
10     #   curra = a->data
11     #   currb = b->data
12     #   while i < asize
13     #     i1 = *curra
14     #     i2 = *currb
15     #     if (c1 != c2) return false
16     #     i+=4, curra+=4, currb+=4
17     #   return true
18     #
19     # registers:
20     #   i: ecx
21     #   asize: edx
22     #   curra: esi
23     #   currb: edi
24     #   i1: eax
25     #   i2: ebx
26     #
27     # . prologue
28     55/push-ebp
29     89/<- %ebp 4/r32/esp
30     # . save registers
31     51/push-ecx
32     52/push-edx
33     53/push-ebx
34     56/push-esi
35     57/push-edi
36     # esi = a
37     8b/-> *(ebp+8) 6/r32/esi
38     # edi = b
39     8b/-> *(ebp+0xc) 7/r32/edi
40     # var asize/edx: int = a->size
41     8b/-> *esi 2/r32/edx
42 $array-equal?:sizes:
43     # if (asize != b->size) return false
44     39/compare *edi 2/r32/edx
45     75/jump-if-!= $array-equal?:false/disp8
46     # var curra/esi: (addr byte) = a->data
47     81 0/subop/add %esi 4/imm32
48     # var currb/edi: (addr byte) = b->data
49     81 0/subop/add %edi 4/imm32
50     # var i/ecx: int = 0
51     31/xor-with %ecx 1/r32/ecx
52     # var vala/eax: int
53     # var valb/ebx: int
54 $array-equal?:loop:
55     # if (i >= asize) return true
56     39/compare %ecx 2/r32/edx
57     7d/jump-if->= $array-equal?:true/disp8
58     # var vala/eax: int = *curra
59     8b/-> *esi 0/r32/eax
60     # var valb/ebx: int = *currb
61     8b/-> *edi 3/r32/ebx
62     # if (vala != valb) return false
63     39/compare %eax 3/r32/ebx
64     75/jump-if-!= $array-equal?:false/disp8
65     # i += 4
66     81 0/subop/add %ecx 4/imm32
67     # currs += 4
68     81 0/subop/add %esi 4/imm32
69     # currb += 4
70     81 0/subop/add %edi 4/imm32
71     eb/jump $array-equal?:loop/disp8
72 $array-equal?:true:
73     b8/copy-to-eax 1/imm32
74     eb/jump $array-equal?:end/disp8
75 $array-equal?:false:
76     b8/copy-to-eax 0/imm32
77 $array-equal?:end:
78     # . restore registers
79     5f/pop-to-edi
80     5e/pop-to-esi
81     5b/pop-to-ebx
82     5a/pop-to-edx
83     59/pop-to-ecx
84     # . epilogue
85     89/<- %esp 5/r32/ebp
86     5d/pop-to-ebp
87     c3/return
89 test-compare-empty-with-empty-array:
90     # . prologue
91     55/push-ebp
92     89/<- %ebp 4/r32/esp
93     # var ecx: (array _) = []
94     68/push 0/imm32/size
95     89/<- %ecx 4/r32/esp
96     # var edx: (array _) = []
97     68/push 0/imm32/size
98     89/<- %edx 4/r32/esp
99     #
100     (array-equal? %ecx %edx)  # => eax
101     (check-ints-equal %eax 1 "F - test-compare-empty-with-empty-array")
102     # . epilogue
103     89/<- %esp 5/r32/ebp
104     5d/pop-to-ebp
105     c3/return
107 test-compare-empty-with-non-empty-array:  # also checks size-mismatch code path
108     # . prologue
109     55/push-ebp
110     89/<- %ebp 4/r32/esp
111     # var ecx: (array int) = [1]
112     68/push 1/imm32
113     68/push 4/imm32/size
114     89/<- %ecx 4/r32/esp
115     # var edx: (array int) = []
116     68/push 0/imm32/size
117     89/<- %edx 4/r32/esp
118     #
119     (array-equal? %ecx %edx)  # => eax
120     (check-ints-equal %eax 0 "F - test-compare-empty-with-non-empty-array")
121     # . epilogue
122     89/<- %esp 5/r32/ebp
123     5d/pop-to-ebp
124     c3/return
126 test-compare-equal-arrays:
127     # . prologue
128     55/push-ebp
129     89/<- %ebp 4/r32/esp
130     # var ecx: (array int) = [1, 2, 3]
131     68/push 3/imm32
132     68/push 2/imm32
133     68/push 1/imm32
134     68/push 0xc/imm32/size
135     89/<- %ecx 4/r32/esp
136     # var edx: (array int) = [1, 2, 3]
137     68/push 3/imm32
138     68/push 2/imm32
139     68/push 1/imm32
140     68/push 0xc/imm32/size
141     89/<- %edx 4/r32/esp
142     #
143     (array-equal? %ecx %edx)  # => eax
144     (check-ints-equal %eax 1 "F - test-compare-equal-arrays")
145     # . epilogue
146     89/<- %esp 5/r32/ebp
147     5d/pop-to-ebp
148     c3/return
150 test-compare-inequal-arrays-equal-sizes:
151     # . prologue
152     55/push-ebp
153     89/<- %ebp 4/r32/esp
154     # var ecx: (array int) = [1, 4, 3]
155     68/push 3/imm32
156     68/push 4/imm32
157     68/push 1/imm32
158     68/push 0xc/imm32/size
159     89/<- %ecx 4/r32/esp
160     # var edx: (array int) = [1, 2, 3]
161     68/push 3/imm32
162     68/push 2/imm32
163     68/push 1/imm32
164     68/push 0xc/imm32/size
165     89/<- %edx 4/r32/esp
166     #
167     (array-equal? %ecx %edx)  # => eax
168     (check-ints-equal %eax 0 "F - test-compare-inequal-arrays-equal-sizes")
169     # . epilogue
170     89/<- %esp 5/r32/ebp
171     5d/pop-to-ebp
172     c3/return
174 _parse-array-of-ints:  # ad: (addr allocation-descriptor), s: (addr array byte), out: (addr handle array int)
175     # pseudocode
176     #   end = &s->data[s->size]
177     #   curr = s->data
178     #   size = 0
179     #   while true
180     #     if (curr >= end) break
181     #     curr = skip-chars-matching-in-slice(curr, end, ' ')
182     #     if (curr >= end) break
183     #     curr = skip-chars-not-matching-in-slice(curr, end, ' ')
184     #     ++size
185     #   allocate-array(ad, size*4, out)
186     #   var slice: slice = {s->data, 0}
187     #   curr = lookup(out)->data
188     #   while true
189     #     if (slice->start >= end) break
190     #     slice->start = skip-chars-matching-in-slice(slice->start, end, ' ')
191     #     if (slice->start >= end) break
192     #     slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ')
193     #     *curr = parse-hex-int-from-slice(slice)
194     #     curr += 4
195     #     slice->start = slice->end
196     #   return result
197     #
198     # . prologue
199     55/push-ebp
200     89/<- %ebp 4/r32/esp
201     # . save registers
202     50/push-eax
203     51/push-ecx
204     52/push-edx
205     53/push-ebx
206     56/push-esi
207     57/push-edi
208     # esi = s
209     8b/-> *(ebp+0xc) 6/r32/esi
210     # var curr/ecx: (addr byte) = s->data
211     8d/copy-address *(esi+4) 1/r32/ecx
212     # var end/edx: (addr byte) = &s->data[s->size]
213     # . edx = s->size
214     8b/-> *esi 2/r32/edx
215     # . edx += curr
216     01/add-to %edx 1/r32/ecx
217     # var size/ebx: int = 0
218     31/xor-with %ebx 3/r32/ebx
219 $_parse-array-of-ints:loop1:
220     # if (curr >= end) break
221     39/compare %ecx 2/r32/edx
222     73/jump-if-addr>= $_parse-array-of-ints:break1/disp8
223     # curr = skip-chars-matching-in-slice(curr, end, ' ')
224     (skip-chars-matching-in-slice %ecx %edx 0x20)  # => eax
225     89/<- %ecx 0/r32/eax
226     # if (curr >= end) break
227     39/compare %ecx 2/r32/edx
228     73/jump-if-addr>= $_parse-array-of-ints:break1/disp8
229     # curr = skip-chars-not-matching-in-slice(curr, end, ' ')
230     (skip-chars-not-matching-in-slice %ecx %edx 0x20)  # => eax
231     89/<- %ecx 0/r32/eax
232     # size += 4
233     81 0/subop/add %ebx 4/imm32
234     eb/jump $_parse-array-of-ints:loop1/disp8
235 $_parse-array-of-ints:break1:
236     (allocate-array *(ebp+8) %ebx *(ebp+0x10))
237 $_parse-array-of-ints:pass2:
238     # var slice/edi: slice = {s->data, 0}
239     68/push 0/imm32/end
240     8d/copy-address *(esi+4) 7/r32/edi
241     57/push-edi
242     89/<- %edi 4/r32/esp
243     # curr = lookup(out)->data
244     8b/-> *(ebp+0x10) 0/r32/eax
245     (lookup *eax *(eax+4))  # => eax
246     8d/copy-address *(eax+4) 1/r32/ecx
247 $_parse-array-of-ints:loop2:
248     # if (slice->start >= end) break
249     39/compare *edi 2/r32/edx
250     73/jump-if-addr>= $_parse-array-of-ints:end/disp8
251     # slice->start = skip-chars-matching-in-slice(slice->start, end, ' ')
252     (skip-chars-matching-in-slice *edi %edx 0x20)  # => eax
253     89/<- *edi 0/r32/eax
254     # if (slice->start >= end) break
255     39/compare *edi 2/r32/edx
256     73/jump-if-addr>= $_parse-array-of-ints:end/disp8
257     # slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ')
258     (skip-chars-not-matching-in-slice *edi %edx 0x20)  # => eax
259     89/<- *(edi+4) 0/r32/eax
260     # *curr = parse-hex-int-from-slice(slice)
261     (parse-hex-int-from-slice %edi)
262     89/<- *ecx 0/r32/eax
263     # curr += 4
264     81 0/subop/add %ecx 4/imm32
265     # slice->start = slice->end
266     8b/-> *(edi+4) 0/r32/eax
267     89/<- *edi 0/r32/eax
268     eb/jump $_parse-array-of-ints:loop2/disp8
269 $_parse-array-of-ints:end:
270     # . reclaim locals
271     81 0/subop/add %esp 8/imm32
272     # . restore registers
273     5f/pop-to-edi
274     5e/pop-to-esi
275     5b/pop-to-ebx
276     5a/pop-to-edx
277     59/pop-to-ecx
278     58/pop-to-eax
279     # . epilogue
280     89/<- %esp 5/r32/ebp
281     5d/pop-to-ebp
282     c3/return
284 test-parse-array-of-ints:
285     # . prologue
286     55/push-ebp
287     89/<- %ebp 4/r32/esp
288     # var h/esi: (handle array int)
289     68/push 0/imm32
290     68/push 0/imm32
291     89/<- %esi 4/r32/esp
292     # var ecx: (array int) = [1, 2, 3]
293     68/push 3/imm32
294     68/push 2/imm32
295     68/push 1/imm32
296     68/push 0xc/imm32/size
297     89/<- %ecx 4/r32/esp
298     #
299     (_parse-array-of-ints Heap "1 2 3" %esi)
300     (lookup *esi *(esi+4))  # => eax
301     (array-equal? %ecx %eax)  # => eax
302     (check-ints-equal %eax 1 "F - test-parse-array-of-ints")
303     # . epilogue
304     89/<- %esp 5/r32/ebp
305     5d/pop-to-ebp
306     c3/return
308 test-parse-array-of-ints-empty:
309     # - empty string = empty array
310     # . prologue
311     55/push-ebp
312     89/<- %ebp 4/r32/esp
313     # var h/esi: handle
314     68/push 0/imm32
315     68/push 0/imm32
316     89/<- %esi 4/r32/esp
317     #
318     (_parse-array-of-ints Heap "" %esi)
319     (lookup *esi *(esi+4))  # => eax
320     (check-ints-equal *eax 0 "F - test-parse-array-of-ints-empty")
321     # . epilogue
322     89/<- %esp 5/r32/ebp
323     5d/pop-to-ebp
324     c3/return
326 test-parse-array-of-ints-just-whitespace:
327     # - just whitespace = empty array
328     # . prologue
329     55/push-ebp
330     89/<- %ebp 4/r32/esp
331     # var h/esi: handle
332     68/push 0/imm32
333     68/push 0/imm32
334     89/<- %esi 4/r32/esp
335     #
336     (_parse-array-of-ints Heap Space %esi)
337     (lookup *esi *(esi+4))  # => eax
338     (check-ints-equal *eax 0 "F - test-parse-array-of-ints-just-whitespace")
339     # . epilogue
340     89/<- %esp 5/r32/ebp
341     5d/pop-to-ebp
342     c3/return
344 test-parse-array-of-ints-extra-whitespace:
345     # . prologue
346     55/push-ebp
347     89/<- %ebp 4/r32/esp
348     # var h/esi: handle
349     68/push 0/imm32
350     68/push 0/imm32
351     89/<- %esi 4/r32/esp
352     # var ecx: (array int) = [1, 2, 3]
353     68/push 3/imm32
354     68/push 2/imm32
355     68/push 1/imm32
356     68/push 0xc/imm32/size
357     89/<- %ecx 4/r32/esp
358     #
359     (_parse-array-of-ints Heap " 1 2  3  " %esi)
360     (lookup *esi *(esi+4))  # => eax
361     (array-equal? %ecx %eax)  # => eax
362     (check-ints-equal %eax 1 "F - test-parse-array-of-ints-extra-whitespace")
363     # . epilogue
364     89/<- %esp 5/r32/ebp
365     5d/pop-to-ebp
366     c3/return
368 parse-array-of-ints:  # s: (addr array byte), out: (addr handle array int)
369     # . prologue
370     55/push-ebp
371     89/<- %ebp 4/r32/esp
372     #
373     (_parse-array-of-ints Heap *(ebp+8) *(ebp+0xc))
374 $parse-array-of-ints:end:
375     # . epilogue
376     89/<- %esp 5/r32/ebp
377     5d/pop-to-ebp
378     c3/return
380 # helper for later tests
381 # compare an array with a string representation of an array literal
382 check-array-equal:  # a: (addr array int), expected: (addr string), msg: (addr string)
383     # . prologue
384     55/push-ebp
385     89/<- %ebp 4/r32/esp
386     # . save registers
387     50/push-eax
388     56/push-esi
389     # var h/esi: handle
390     68/push 0/imm32
391     68/push 0/imm32
392     89/<- %esi 4/r32/esp
393     # var b/eax: (addr array int) = parse-array-of-ints(Heap, expected)
394     (parse-array-of-ints *(ebp+0xc) %esi)
395     (lookup *esi *(esi+4))  # => eax
396     #
397     (array-equal? *(ebp+8) %eax)
398     (check-ints-equal %eax 1 *(ebp+0x10))
399 $check-array-equal:end:
400     # . restore registers
401     5e/pop-to-esi
402     58/pop-to-eax
403     # . epilogue
404     89/<- %esp 5/r32/ebp
405     5d/pop-to-ebp
406     c3/return
408 test-check-array-equal:
409     # . prologue
410     55/push-ebp
411     89/<- %ebp 4/r32/esp
412     # var ecx: (array int) = [1, 2, 3]
413     68/push 3/imm32
414     68/push 2/imm32
415     68/push 1/imm32
416     68/push 0xc/imm32/size
417     89/<- %ecx 4/r32/esp
418     #
419     (check-array-equal %ecx "1 2 3" "F - test-check-array-equal")
420     # . epilogue
421     89/<- %esp 5/r32/ebp
422     5d/pop-to-ebp
423     c3/return
425 == data
427 # length-prefixed string containing just a single space
428 Space:  # (array byte)
429     # size: int
430     1/imm32
431     # data
432     20/space