mescc: Tinycc support: pointer arithmetic.
[mes.git] / module / mes / as-i386.mes
1 ;;; -*-scheme-*-
2
3 ;;; Mes --- Maxwell Equations of Software
4 ;;; Copyright © 2016,2017 Jan Nieuwenhuizen <janneke@gnu.org>
5 ;;;
6 ;;; This file is part of Mes.
7 ;;;
8 ;;; Mes is free software; you can redistribute it and/or modify it
9 ;;; under the terms of the GNU General Public License as published by
10 ;;; the Free Software Foundation; either version 3 of the License, or (at
11 ;;; your option) any later version.
12 ;;;
13 ;;; Mes is distributed in the hope that it will be useful, but
14 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ;;; GNU General Public License for more details.
17 ;;;
18 ;;; You should have received a copy of the GNU General Public License
19 ;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
20
21 ;;; Commentary:
22
23 ;;; as-i386.mes defines i386 assembly
24
25 ;;; Code:
26
27 (cond-expand
28  (guile-2)
29  (guile)
30  (mes
31   (mes-use-module (mes as))))
32
33 (define (i386:nop)
34   '(("nop")))
35
36 (define (i386:function-preamble)
37   '(("push___%ebp")
38     ("mov____%esp,%ebp")))
39
40 (define (i386:function-locals)
41   `(("sub____%esp,$i32" (#:immediate ,(+ (* 4 1025) (* 20 4)))))) ; sub %esp,xxx 4*1024 buf, 20 local vars
42
43 (define (i386:push-label label)
44   `(("push___$i32" (#:address ,label)))) ; push  $0x<label>
45
46 (define (i386:push-label-mem label)
47   `(("mov____0x32,%eax" (#:address ,label)) ; mov    0x804a000,%eax
48     ("push___%eax")))                       ; push  %eax
49
50
51 ;;; \f locals
52
53 (define (i386:push-local n)
54   (or n (error "invalid value: push-local: " n))
55   (let ((n (- 0 (* 4 n))))
56     `(,(if (< (abs n) #x80) `("push___0x8(%ebp)" (#:immediate1 ,n))
57            `("push___0x32(%ebp)" (#:immediate ,n))))))
58
59 (define (i386:push-local-address n)
60   (or n (error "invalid value: push-local-address: " n))
61   (let ((n (- 0 (* 4 n))))
62     `(,(if (< (abs n) #x80) `("lea____0x8(%ebp),%eax" (#:immediate1 ,n))
63            `("lea____0x32(%ebp),%eax" (#:immediate ,n)))
64       ("push___%eax"))))
65
66 (define (i386:push-byte-local-de-ref n)
67   (or n (error "invalid value: push-byte-local-de-ref: " n))
68   (let ((n (- 0 (* 4 n))))
69     `(,(if (< (abs n) #x80) `("mov____0x8(%ebp),%eax" (#:immediate1 ,n))
70            `("mov____0x32(%ebp),%eax" (#:immediate ,n)))
71       ("movzbl_(%eax),%eax")
72       ("push___%eax"))))
73
74 (define (i386:push-byte-local-de-de-ref n)
75   (or n (error "invalid value: push-byte-local-de-de-ref: " n))
76   (let ((n (- 0 (* 4 n))))
77     `(,(if (< (abs n) #x80) `("mov____0x8(%ebp),%eax" (#:immediate1 ,n))
78            `("mov____0x32(%ebp),%eax" (#:immediate ,n)))
79       ("mov____(%eax),%eax")
80       ("movzbl_(%eax),%eax")
81       ("push___%eax"))))
82
83 (define (i386:push-local-de-ref n)
84   (or n (error "invalid value: push-byte-local-de-ref: " n))
85   (let ((n (- 0 (* 4 n))))
86     `(,(if (< (abs n) #x80) `("mov____0x8(%ebp),%eax" (#:immediate1 ,n))
87            `("mov____0x32(%ebp),%eax" (#:immediate ,n)))
88       ("mov____(%eax),%eax")
89       ("push___%eax"))))
90
91 (define (i386:local-add n v)
92   (or n (error "invalid value: i386:local-add: " n))
93   (let ((n (- 0 (* 4 n))))
94     `(,(if (and (< (abs n) #x80)
95                 (< (abs v) #x80)) `("add____$i8,0x8(%ebp)" (#:immediate1 ,n) (#:immediate1 ,v))
96                 `("add____$i32,0x32(%ebp)" (#:immediate ,n) (#:immediate ,v))))))
97
98 (define (i386:accu->local n)
99   (or n (error "invalid value: accu->local: " n))
100   (let ((n (- 0 (* 4 n))))
101     `(,(if (< (abs n) #x80) `("mov____%eax,0x8(%ebp)" (#:immediate1 ,n))
102            `("mov____%eax,0x32(%ebp)" (#:immediate ,n))))))
103
104 (define (i386:base->local n)
105   (or n (error "invalid value: base->local: " n))
106   `(("mov____%edx,0x8(%ebp)" ,(- 0 (* 4 n))))) ; mov    %edx,-<0xn>(%ebp)
107
108 (define (i386:base->local n)
109   (or n (error "invalid value: base->local: " n))
110   (let ((n (- 0 (* 4 n))))
111     `((if (< (abs n) #x80) `("mov____%edx,0x8(%ebp)" (#:immediate1 ,n))
112           `("mov____%edx,0x32(%ebp)" (#:immediate ,n))))))
113
114 (define (i386:local->accu n)
115   (or n (error "invalid value: local->accu: " n))
116   (let ((n (- 0 (* 4 n))))
117     `(,(if (< (abs n) #x80) `("mov____0x8(%ebp),%eax" (#:immediate1 ,n))
118            `("mov____0x32(%ebp),%eax" (#:immediate ,n))))))
119
120 (define (i386:local-address->accu n)
121   (or n (error "invalid value: ladd: " n))
122   (let ((n (- 0 (* 4 n))))
123     `(,(if (< (abs n) #x80) `("lea____0x8(%ebp),%eax" (#:immediate1 ,n))
124            `("lea____0x32(%ebp),%eax" (#:immediate ,n))))))
125
126 (define (i386:local-ptr->accu n)
127   (or n (error "invalid value: local-ptr->accu: " n))
128   (let ((n (- 0 (* 4 n))))
129   `(("mov____%ebp,%eax")                ; mov    %ebp,%eax
130     ,(if (< (abs n) #x80) `("add____$i8,%eax" (#:immediate1 ,n))
131          `("add____$i32,%eax" (#:immediate ,n))))))
132
133 (define (i386:byte-local->accu n)
134   (or n (error "invalid value: byte-local->accu: " n))
135   (let ((n (- 0 (* 4 n))))
136     `(,(if (< (abs n) #x80) `("movzbl_0x8(%ebp),%eax" (#:immediate1 ,n))
137            `("movzbl_0x32(%ebp),%eax" (#:immediate ,n))))))
138
139 (define (i386:byte-local->base n)
140   (or n (error "invalid value: byte-local->base: " n))
141   (let ((n (- 0 (* 4 n))))
142     `(,(if (< (abs n) #x80) `("movzbl_0x8(%ebp),%edx" (#:immediate1 ,n))
143            `,@(("mov_0x32(%ebp),%edx" (#:immediate ,n))
144                ("movzbl_%dl,%edx"))))))
145
146 (define (i386:local->base n)
147   (or n (error "invalid value: local->base: " n))
148   (let ((n (- 0 (* 4 n))))
149     `(,(if (< (abs n) #x80) `("mov____0x8(%ebp),%edx" (#:immediate1 ,n))
150            `("mov____0x32(%ebp),%edx" (#:immediate ,n))))))
151
152 (define (i386:local-address->base n) ;; DE-REF
153   (or n (error "invalid value: local-address->base: " n))
154   (let ((n (- 0 (* 4 n))))
155     `(,(if (< (abs n) #x80) `("lea____0x8(%ebp),%edx" (#:immediate1 ,n))
156            `("lea____0x32(%ebp),%edx" (#:immediate ,n))))))
157
158 (define (i386:local-ptr->base n)
159   (or n (error "invalid value: local-ptr->base: " n))
160   (let ((n (- 0 (* 4 n))))
161     `(("mov____%ebp,%edx")                ; mov    %ebp,%edx
162       ,(if (< (abs n) #x80) `("add____$i8,%edx" (#:immediate1 ,n))
163            `("add____$i32,%edx" (#:immediate ,n))))))
164
165 (define (i386:value->local n v)
166   (or n (error "invalid value: value->local: " n))
167   (let ((n (- 0 (* 4 n))))
168     `(,(if (< (abs n) #x80) `("mov____$i32,0x8(%ebp)" (#:immediate1 ,n) (#:immediate ,v))
169            `("mov____$i32,0x32(%ebp)" (#:immediate ,n) (#:immediate ,v))))))
170
171 (define (i386:local-test n v)
172   (or n (error "invalid value: local-test: " n))
173   (let ((n (- 0 (* 4 n))))
174     `(,(cond ((and (< (abs n) #x80)
175                    (< (abs v) #x80)) `("cmp____$i8,0x8(%ebp)" (#:immediate1 ,n) (#:immediate1 ,v)))
176              ((< (abs n) #x80) `("cmp____$i32,0x8(%ebp)" (#:immediate1 ,n) (#:immediate ,v)))
177              ((< (abs v) #x80) `("cmp____$i8,0x32(%ebp)" (#:immediate ,n) (#:immediate1 ,v)))
178              (else `("cmp____$i32,0x32(%ebp)" (#:immediate ,n) (#:immediate ,v)))))))
179
180 (define (i386:pop-accu)
181   '(("pop____%eax")))                   ; pop %eax
182
183 (define (i386:push-accu)
184   '(("push___%eax")))                   ; push %eax
185
186 (define (i386:pop-base)
187   '(("pop____%edx")))                   ; pop %edx
188
189 (define (i386:push-base)
190   '(("push___%edx")))                   ; push %edx
191
192 (define (i386:ret)
193   '(("leave")                           ; leave
194     ("ret")))                           ; ret
195
196 (define (i386:accu->base)
197   '(("mov____%eax,%edx")))              ; mov    %eax,%edx
198
199 (define (i386:accu->base-address)
200   '(("mov____%eax,(%edx)")))            ; mov    %eax,(%edx)
201
202 (define (i386:byte-accu->base-address)
203   '(("mov____%al,(%edx)")))             ; mov    %al,(%edx)
204
205 (define (i386:accu->base-address+n n)
206   (or n (error "invalid value: accu->base-address+n: " n))
207   `(,(if (< (abs n) #x80) `("mov____%eax,0x8(%edx)" (#:immediate1 ,n))
208          `("mov____%eax,0x32(%edx)" (#:immediate ,n)))))
209
210 (define (i386:accu->label label)
211   `(("mov____%eax,0x32" (#:address ,label)))) ; mov    %eax,0x<label>
212
213 (define (i386:accu-zero?)
214   '(("test___%eax,%eax")))
215
216 (define (i386:accu-shl n)
217   (or n (error "invalid value: accu:shl n: " n))
218   `(("shl____$i8,%eax" (#:immediate1 ,n)))) ; shl    $0x8,%eax
219
220 (define (i386:accu<<base)
221   '(("xor____%ecx,%ecx")                ; xor    %ecx,%ecx
222     ("mov____%edx,%ecx")                ; mov    %edx,%ecx
223     ("shl____%cl,%eax")))               ; shl    %cl,%eax
224
225 (define (i386:accu>>base)
226   '(("xor____%ecx,%ecx")                ; xor    %ecx,%ecx
227     ("mov____%edx,%ecx")                ; mov    %edx,%ecx
228     ("shr____%cl,%eax")))               ; shr    %cl,%eax
229
230 (define (i386:accu-and-base)
231   '(("and____%edx,%eax")))              ; and    %edx,%eax
232
233 (define (i386:accu-not)
234   '(("not____%eax")))                   ; not %eax
235
236 (define (i386:accu-or-base)
237   '(("or_____%edx,%eax")))              ; or    %edx,%eax
238
239 (define (i386:accu-xor-base)
240   '(("xor____%edx,%eax")))              ; xor    %edx,%eax
241
242 (define (i386:accu+accu)
243   '(("add____%eax,%eax")))              ; add    %eax,%eax
244
245 (define (i386:accu+base)
246   `(("add____%edx,%eax")))              ; add    %edx,%eax
247
248 (define (i386:accu+value v)
249   `(,(if (< (abs v) #x80) `("add____$i8,%eax" (#:immediate1 ,v))
250          `("add____$i32,%eax" (#:immediate ,v)))))
251
252 (define (i386:base+value v)
253   `(,(if (< (abs v) #x80) `("add____$i8,%edx" (#:immediate1 ,v))
254          `("add____$i32,%edx" (#:immediate ,v)))))
255
256 (define (i386:accu-base)
257   `(("sub____%edx,%eax")))              ; sub    %edx,%eax
258
259 (define (i386:accu*base)
260   `(("mul____%edx")))                   ; mul    %edx
261
262 (define (i386:accu/base)
263   '(("mov____%edx,%ebx")                ; mov    %edx,%ebx
264     ("xor____%edx,%edx")                ; xor    %edx,%edx
265     ("div____%ebx")))                   ; div    %ebx
266
267 (define (i386:accu%base)
268   '(("mov____%edx,%ebx")                ; mov    %edx,%ebx
269     ("xor____%edx,%edx")                ; xor    %edx,%edx
270     ("div____%ebx")                     ; div    %ebx
271     ("mov____%edx,%eax")))              ; mov    %edx,%eax
272
273 (define (i386:base->accu)
274   '(("mov____%edx,%eax")))              ; mov    %edx,%eax
275
276 (define (i386:label->accu label)
277   `(("mov____$i32,%eax" (#:address ,label)))) ; mov    $<n>,%eax
278
279 (define (i386:label->base label)
280   `(("mov____$i32,%edx" (#:address ,label)))) ; mov   $<n>,%edx
281
282 (define (i386:label-mem->accu label)
283   `(("mov____0x32,%eax" (#:address ,label)))) ; mov    0x<n>,%eax
284
285 (define (i386:label-mem->base label)
286   `(("mov____0x32,%edx" (#:address ,label)))) ; mov    0x<n>,%edx
287
288 (define (i386:label-mem-add label v)
289   `(,(if (< (abs v) #x80) `("add____$i8,0x32" (#:address ,label) (#:immediate1 ,v))
290          `("add____$i32,0x32" (#:address ,label) (#:immediate ,v)))))
291
292 (define (i386:byte-base-mem->accu)
293   '(("add____%edx,%eax")                ; add    %edx,%eax
294     ("movzbl_(%eax),%eax")))            ; movzbl (%eax),%eax
295
296 (define (i386:byte-mem->accu)
297   '(("movzbl_(%eax),%eax")))            ; movzbl (%eax),%eax
298
299 (define (i386:byte-mem->base)
300   '(("movzbl_(%edx),%edx")))            ; movzbl (%edx),%edx
301
302 (define (i386:base-mem->accu)
303   '(("add___%edx,%eax")                 ; add    %edx,%eax
304     ("mov____(%eax),%eax")))            ; mov    (%eax),%eax
305
306 (define (i386:mem->accu)
307   '(("mov____(%eax),%eax")))            ; mov    (%eax),%eax
308
309 (define (i386:mem->base)
310   '(("mov____(%edx),%edx")))            ; mov    (%edx),%edx
311
312 (define (i386:mem+n->accu n)
313   `(,(if (< (abs n) #x80) `("mov____0x8(%eax),%eax" (#:immediate1 ,n))
314          `("mov____0x32(%eax),%eax" (#:immediate ,n)))))
315
316 (define (i386:base-mem+n->accu v)
317   (or v (error "invalid value: base-mem+n->accu: " v))
318   `(("add___%edx,%eax")
319     ,(if (< (abs v) #x80) `("mov____0x8(%eax),%eax" (#:immediate1 ,v))
320          `("mov____0x32(%eax),%eax" (#:immediate ,v)))))
321
322 (define (i386:value->accu v)
323   (or v (error "invalid value: i386:value->accu: " v))
324   `(("mov____$i32,%eax" (#:immediate ,v)))) ; mov    $<v>,%eax
325
326 (define (i386:value->accu-address v)
327   `(("mov____$i32,(%eax)" (#:immediate ,v)))) ; movl   $0x<v>,(%eax)
328
329 (define (i386:value->accu-address+n n v)
330   (or v (error "invalid value: i386:value->accu-address+n: " v))
331   `(,(if (< (abs v) #x80) `("mov____$i32,0x8(%eax)" (#:immediate1 ,n) (#:immediate ,v))
332          `("mov____$i32,0x32(%eax)" (#:immediate ,n) (#:immediate ,v)))))
333
334 (define (i386:base->accu-address)
335   '(("mov____%edx,%(eax)")))            ; mov    %edx,(%eax)
336
337 (define (i386:base-address->accu-address)
338   '(("mov____(%edx),%ecx")              ; mov    (%edx),%ecx
339     ("mov____%ecx,%(eax)")))            ; mov    %ecx,(%eax)
340
341 (define (i386:byte-base->accu-address)
342   '(("mov____%dl,(%eax)")))             ; mov    %dl,(%eax)
343
344 (define (i386:byte-base->accu-address+n n)
345   (or n (error "invalid value: byte-base->accu-address+n: " n))
346   `(,(if (< (abs n) #x80) `("mov____%dl,0x8(%eax)" (#:immediate1 ,n))
347          `("mov____%dl,0x32(%eax)" (#:immediate ,n)))))
348
349 (define (i386:value->base v)
350   (or v (error "invalid value: i386:value->base: " v))
351   `(("mov____$i32,%edx" (#:immediate ,v)))) ; mov    $<v>,%edx
352
353 (define (i386:accu-mem-add v)
354   `(,(if (< (abs v) #x80) `("add____$i8,(%eax)" (#:immediate1 ,v))
355          `("add____$i32,(%eax)" (#:immediate ,v)))))
356
357 (define (i386:value->label label v)
358   (or v (error "invalid value: value->label: " v))
359   `(("mov____$i32,0x32" (#:address ,label)
360      (#:immediate ,v))))
361
362 (define (i386:call-label label n)
363   `((call32 (#:offset ,label))
364     ("add____$i8,%esp" (#:immediate1 ,(* n 4)))))
365
366 (define (i386:call-accu n)
367   `(,@(i386:push-accu)
368     ,@(i386:pop-accu)
369     ("call___*%eax")                    ; call   *%eax
370     ("add____$i8,%esp" (#:immediate1  ,(* n 4))))) ; add    $00,%esp
371
372 (define (i386:accu-negate)
373   '(("sete___%al")                      ; sete %al
374     ("movzbl_%al,%eax")))               ; movzbl %al,%eax
375
376 (define (i386:xor-accu v)
377   (or v (error "invalid value: i386:xor-accu: n: " v))
378   `(("xor___$i32,%eax" (#:immediate ,v)))) ;xor    $0xff,%eax
379
380 (define (i386:xor-zf)
381   '(("lahf")                               ; lahf
382     ("xor____$i8,%ah" (#:immediate1 #x40)) ; xor    $0x40,%ah
383     ("sahf")))                             ; sahf
384
385 (define (i386:accu-cmp-value v)
386   `(,(if (< (abs v) #x80) `("cmp____$i8,%eax" (#:immediate1 ,v))
387          `("cmp____$i32,%eax" (#:immediate ,v)))))
388
389 (define (i386:accu-test)
390   '(("test___%eax,%eax")))              ; test   %eax,%eax
391
392 (define (i386:jump label)
393   `(("jmp32 " (#:offset ,label))))
394
395 (define (i386:jump-z label)
396   `(("je32  " (#:offset ,label))))        ; jz . + <n>
397
398 (define (i386:jump-byte-z label)
399   `(("test___%al,%al")                  ; test   %al,%al
400     ("je32  " (#:offset ,label))))      ; je <n>
401
402 ;; signed
403 (define (i386:jump-g label)
404   `(("jg32  " (#:offset ,label))))        ; jg/jnle <n>
405
406 ;; signed
407 (define (i386:jump-ge label)
408   `(("jge32 " (#:offset ,label))))       ; jge/jnl <n>
409
410 (define (i386:jump-nz label)
411   `(("jne32 " (#:offset ,label))))       ; jnz . + <n>
412
413 (define (i386:byte-test-base)
414   '(("cmp____%al,%dl")))                ; cmp    %al,%dl
415
416 (define (i386:test-base)
417   (("cmp____%edx,%eax")))               ; cmp    %edx,%eax
418
419 (define (i386:byte-sub-base)
420   '(("sub____%dl,%al")))                ; sub    %dl,%al
421
422 (define (i386:byte-base-sub)
423   `(("sub____%al,%dl")))                ; sub    %al,%dl
424
425 (define (i386:sub-base)
426   `(("sub____%edx,%eax")))              ; sub    %edx,%eax
427
428 (define (i386:base-sub)
429   `(("sub____%eax,%edx")))              ; sub    %eax,%edx
430
431 (define (i386:nz->accu)
432   '(("setne__%al")                      ; setne   %al
433     ("movzbl_%al,%eax")))               ; movzbl %al,%eax
434
435 (define (i386:z->accu)
436   '(("sete___%al")                      ; sete   %al
437     ("movzbl_%al,%eax")))               ; movzbl %al,%eax
438
439 (define (i386:accu<->stack)
440   '(("xchg___%eax,(%esp)")))            ; xchg   %eax,(%esp)