1 ;;; GNU Mes --- Maxwell Equations of Software
2 ;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
4 ;;; This file is part of GNU Mes.
6 ;;; GNU Mes is free software; you can redistribute it and/or modify it
7 ;;; under the terms of the GNU General Public License as published by
8 ;;; the Free Software Foundation; either version 3 of the License, or (at
9 ;;; your option) any later version.
11 ;;; GNU Mes is distributed in the hope that it will be useful, but
12 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ;;; GNU General Public License for more details.
16 ;;; You should have received a copy of the GNU General Public License
17 ;;; along with GNU Mes. If not, see <http://www.gnu.org/licenses/>.
21 ;;; define i386 assembly
25 (define-module (mescc i386 as)
26 #:use-module (mes guile)
27 #:use-module (mescc as)
28 #:use-module (mescc info)
37 (string-append (string-drop-right (string-drop o 1) 1) "l"))
40 (define (i386:function-preamble . rest)
42 ("mov____%esp,%ebp")))
44 (define (i386:function-locals . rest)
45 `(("sub____$i32,%esp" (#:immediate ,(+ (* 4 1025) (* 20 4)))))) ; 4*1024 buf, 20 local vars
47 (define (i386:r->local info n)
48 (or n (error "invalid value: i386:r->local: " n))
49 (let ((r (get-r info))
51 `(,(if (< (abs n) #x80) `(,(string-append "mov____%" r ",0x8(%ebp)") (#:immediate1 ,n))
52 `(,(string-append "mov____%" r ",0x32(%ebp)") (#:immediate ,n))))))
54 (define (i386:value->r info v)
55 (let ((r (get-r info)))
56 `((,(string-append "mov____$i32,%" r) (#:immediate ,v)))))
58 (define (i386:ret . rest)
62 (define (i386:r-zero? info)
63 (let ((r (get-r info)))
64 `((,(string-append "test___%" r "," "%" r)))))
66 (define (i386:local->r info n)
67 (let ((r (get-r info))
69 `(,(if (< (abs n) #x80) `(,(string-append "mov____0x8(%ebp),%" r) (#:immediate1 ,n))
70 `(,(string-append "mov____0x32(%ebp),%" r) (#:immediate ,n))))))
72 (define (i386:r0+r1 info)
73 (let ((r0 (get-r0 info))
75 `((,(string-append "add____%" r1 ",%" r0)))))
77 (define (i386:call-label info label n)
78 `((call32 (#:offset ,label))
79 ("add____$i8,%esp" (#:immediate1 ,(* n 4)))))
81 (define (i386:r->arg info i)
82 (let ((r (get-r info)))
83 `((,(string-append "push___%" r)))))
85 (define (i386:label->arg info label i)
86 `(("push___$i32" (#:address ,label))))
88 (define (i386:r-negate info)
89 (let* ((r (get-r info))
91 `((,(string-append "sete___%" l))
92 (,(string-append "movzbl_%" l ",%" r)))))
94 (define (i386:r0-r1 info)
95 (let ((r0 (get-r0 info))
97 `((,(string-append "sub____%" r1 ",%" r0)))))
99 (define (i386:zf->r info)
100 (let* ((r (get-r info))
102 `((,(string-append "sete___%" l))
103 (,(string-append "movzbl_%" l ",%" r)))))
105 (define (i386:xor-zf info)
107 ("xor____$i8,%ah" (#:immediate1 #x40))
110 (define (i386:r->local+n info id n)
111 (let ((n (+ (- 0 (* 4 id)) n))
113 `(,(if (< (abs n) #x80) `(,(string-append "mov____%" r ",0x8(%ebp)") (#:immediate1 ,n))
114 `(,(string-append "mov____%" r ",0x32(%ebp)") (#:immediate ,n))))))
116 (define (i386:r-mem-add info v)
117 (let ((r (get-r info)))
118 `(,(if (< (abs v) #x80) `(,(string-append "add____$i8,(%" r ")") (#:immediate1 ,v))
119 `(,(string-append "add____$i32,(%" r ")") (#:immediate ,v))))))
121 (define (i386:r-byte-mem-add info v)
122 (let ((r (get-r info)))
123 `((,(string-append "addb___$i8,(%" r ")") (#:immediate1 ,v)))))
125 (define (i386:r-word-mem-add info v)
126 (let ((r (get-r info)))
127 `((,(string-append "addw___$i8,(%" r ")") (#:immediate2 ,v)))))
129 (define (i386:local-ptr->r info n)
130 (let ((r (get-r info)))
131 (let ((n (- 0 (* 4 n))))
132 `((,(string-append "mov____%ebp,%" r))
133 ,(if (< (abs n) #x80) `(,(string-append "add____$i8,%" r) (#:immediate1 ,n))
134 `(,(string-append "add____$i32,%" r) (#:immediate ,n)))))))
136 (define (i386:label->r info label)
137 (let ((r (get-r info)))
138 `((,(string-append "mov____$i32,%" r) (#:address ,label)))))
140 (define (i386:r0->r1 info)
141 (let ((r0 (get-r0 info))
143 `((,(string-append "mov____%" r0 ",%" r1)))))
145 (define (i386:byte-mem->r info)
146 (let ((r (get-r info)))
147 `((,(string-append "movzbl_(%" r "),%" r)))))
149 (define (i386:byte-r info)
150 (let* ((r (get-r info))
152 `((,(string-append "movzbl_%" l ",%" r)))))
154 (define (i386:byte-signed-r info)
155 (let* ((r (get-r info))
157 `((,(string-append "movsbl_%" l ",%" r)))))
159 (define (i386:word-r info)
160 (let* ((r (get-r info))
162 `((,(string-append "movzwl_%" x ",%" r)))))
164 (define (i386:word-signed-r info)
165 (let* ((r (get-r info))
167 `((,(string-append "movswl_%" x ",%" r)))))
169 (define (i386:jump info label)
170 `(("jmp32 " (#:offset ,label))))
172 (define (i386:jump-z info label)
173 `(("je32 " (#:offset ,label))))
175 (define (i386:jump-nz info label)
176 `(("jne32 " (#:offset ,label))))
178 (define (i386:jump-byte-z info label)
180 ("je32 " (#:offset ,label))))
183 (define (i386:jump-g info label)
184 `(("jg32 " (#:offset ,label))))
186 (define (i386:jump-ge info label)
187 `(("jge32 " (#:offset ,label))))
189 (define (i386:jump-l info label)
190 `(("jl32 " (#:offset ,label))))
192 (define (i386:jump-le info label)
193 `(("jle32 " (#:offset ,label))))
196 (define (i386:jump-a info label)
197 `(("ja32 " (#:offset ,label))))
199 (define (i386:jump-ae info label)
200 `(("jae32 " (#:offset ,label))))
202 (define (i386:jump-b info label)
203 `(("jb32 " (#:offset ,label))))
205 (define (i386:jump-be info label)
206 `(("jbe32 " (#:offset ,label))))
208 (define (i386:byte-r0->r1-mem info)
209 (let* ((r0 (get-r0 info))
212 `((,(string-append "mov____%" l0 ",(%" r1 ")")))))
214 (define (i386:label-mem->r info label)
215 (let ((r (get-r info)))
216 `((,(string-append "mov____0x32,%" r) (#:address ,label)))))
218 (define (i386:word-mem->r info)
219 (let ((r (get-r info)))
220 `((,(string-append "movzwl_(%" r "),%" r)))))
222 (define (i386:mem->r info)
223 (let ((r (get-r info)))
224 `((,(string-append "mov____(%" r "),%" r)))))
226 (define (i386:local-add info n v)
227 (let ((n (- 0 (* 4 n))))
228 `(,(if (and (< (abs n) #x80)
229 (< (abs v) #x80)) `("add____$i8,0x8(%ebp)" (#:immediate1 ,n) (#:immediate1 ,v))
230 `("add____$i32,0x32(%ebp)" (#:immediate ,n) (#:immediate ,v))))))
232 (define (i386:label-mem-add info label v)
233 `(,(if (< (abs v) #x80) `("add____$i8,0x32" (#:address ,label) (#:immediate1 ,v))
234 `("add____$i32,0x32" (#:address ,label) (#:immediate ,v)))))
236 (define (i386:nop info)
239 (define (i386:swap-r0-r1 info)
240 (let ((r0 (get-r0 info))
242 `((,(string-append "xchg___%" r0 ",%" r1)))))
245 (define (i386:g?->r info)
246 (let* ((r (get-r info))
248 `((,(string-append "setg___%" l))
249 (,(string-append "movzbl_%" l ",%" r)))))
251 (define (i386:ge?->r info)
252 (let* ((r (get-r info))
254 `((,(string-append "setge__%" l))
255 (,(string-append "movzbl_%" l ",%" r)))))
257 (define (i386:l?->r info)
258 (let* ((r (get-r info))
260 `((,(string-append "setl___%" l))
261 (,(string-append "movzbl_%" l ",%" r)))))
263 (define (i386:le?->r info)
264 (let* ((r (get-r info))
266 `((,(string-append "setle__%" l))
267 (,(string-append "movzbl_%" l ",%" r)))))
270 (define (i386:a?->r info)
271 (let* ((r (get-r info))
273 `((,(string-append "seta___%" l))
274 (,(string-append "movzbl_%" l ",%" r)))))
276 (define (i386:ae?->r info)
277 (let* ((r (get-r info))
279 `((,(string-append "setae__%" l))
280 (,(string-append "movzbl_%" l ",%" r)))))
282 (define (i386:b?->r info)
283 (let* ((r (get-r info))
285 `((,(string-append "setb___%" l))
286 (,(string-append "movzbl_%" l ",%" r)))))
288 (define (i386:be?->r info)
289 (let* ((r (get-r info))
291 `((,(string-append "setbe__%" l))
292 (,(string-append "movzbl_%" l ",%" r)))))
294 (define (i386:test-r info)
295 (let ((r (get-r info)))
296 `((,(string-append "test___%" r ",%" r)))))
298 (define (i386:r->label info label)
299 (let ((r (get-r info)))
300 `((,(string-append "mov____%" r ",0x32") (#:address ,label)))))
302 (define (i386:r->byte-label info label)
303 (let* ((r (get-r info))
305 `((,(string-append "movb___%" l ",0x32") (#:address ,label)))))
307 (define (i386:r->word-label info label)
308 (let* ((r (get-r info))
310 `((,(string-append "movw___%" x ",0x32") (#:address ,label)))))
312 (define (i386:call-r info n)
313 (let ((r (get-r info)))
314 `((,(string-append "call___*%" r))
315 ("add____$i8,%esp" (#:immediate1 ,(* n 4))))))
317 (define (i386:r0*r1 info)
318 (let ((allocated (.allocated info))
321 (if (not (member "edx" allocated))
322 `(,@(if (equal? r0 "eax") '()
324 (,(string-append "mov____%" r0 ",%eax"))))
325 (,(string-append "mul____%" r1))
326 ,@(if (equal? r0 "eax") '()
327 `((,(string-append "mov____%eax,%" r0))
332 (,(string-append "mov____%" r1 ",%ebx"))
333 (,(string-append "mov____%" r0 ",%eax"))
334 (,(string-append "mul____%" r1))
337 (,(string-append "mov____%eax,%" r0))
340 (define (i386:r0<<r1 info)
341 (let ((r0 (get-r0 info))
343 `((,(string-append "mov____%" r1 ",%ecx"))
344 (,(string-append "shl____%cl,%" r0)))))
346 (define (i386:r0>>r1 info)
347 (let ((r0 (get-r0 info))
349 `((,(string-append "mov____%" r1 ",%ecx"))
350 (,(string-append "shr____%cl,%" r0)))))
352 (define (i386:r0-and-r1 info)
353 (let ((r0 (get-r0 info))
355 `((,(string-append "and____%" r1 ",%" r0)))))
357 (define (i386:r0/r1 info signed?)
358 (let ((allocated (.allocated info))
361 (if (not (member "edx" allocated))
362 `(,@(if (equal? r0 "eax") '()
364 (,(string-append "mov____%" r0 ",%eax"))))
365 ,(if signed? '("cltd") '("xor____%edx,%edx"))
366 (,(string-append "idiv___%" r1))
367 ,@(if (equal? r0 "eax") '()
368 `((,(string-append "mov____%eax,%" r0))
373 (,(string-append "mov____%" r1 ",%ebx"))
374 (,(string-append "mov____%" r0 ",%eax"))
375 ,(if signed? '("cltd") '("xor____%edx,%edx"))
376 (,(string-append "idiv___%ebx"))
379 (,(string-append "mov____%eax,%" r0))
382 (define (i386:r0%r1 info signed?)
383 (let ((allocated (.allocated info))
386 (if (not (member "edx" allocated))
387 `(,@(if (equal? r0 "eax") '()
389 (,(string-append "mov____%" r0 ",%eax"))))
390 ,(if signed? '("cltd") '("xor____%edx,%edx"))
391 (,(string-append "idiv___%" r1))
392 (,(string-append "mov____%edx,%" r0)))
396 (,(string-append "mov____%" r1 ",%ebx"))
397 (,(string-append "mov____%" r0 ",%eax"))
398 ,(if signed? '("cltd") '("xor____%edx,%edx"))
399 (,(string-append "idiv___%ebx"))
402 (,(string-append "mov____%edx,%" r0))
405 (define (i386:r+value info v)
406 (let ((r (get-r info)))
407 `(,(if (< (abs v) #x80) `(,(string-append "add____$i8,%" r) (#:immediate1 ,v))
408 `(,(string-append "add____$i32,%" r) (#:immediate ,v))))))
410 (define (i386:r0->r1-mem info)
411 (let ((r0 (get-r0 info))
413 `((,(string-append "mov____%" r0 ",(%" r1 ")")))))
415 (define (i386:byte-r0->r1-mem info)
416 (let* ((r0 (get-r0 info))
419 `((,(string-append "mov____%" l0 ",(%" r1 ")")))))
421 (define (i386:word-r0->r1-mem info)
422 (let* ((r0 (get-r0 info))
425 `((,(string-append "mov____%" x0 ",(%" r1 ")")))))
427 (define (i386:r-cmp-value info v)
428 (let ((r (get-r info)))
429 `(,(if (< (abs v) #x80) `(,(string-append "cmp____$i8,%" r) (#:immediate1 ,v))
430 `(,(string-append "cmp____$i32,%" r) (#:immediate ,v))))))
432 (define (i386:push-register info r)
433 `((,(string-append "push___%" r))))
435 (define (i386:pop-register info r)
436 `((,(string-append "pop____%" r))))
438 (define (i386:return->r info)
439 (let ((r (get-r info)))
440 (if (equal? r "eax") '()
441 `((,(string-append "mov____%eax,%" r))))))
443 (define (i386:r0-or-r1 info)
444 (let ((r0 (get-r0 info))
446 `((,(string-append "or_____%" r1 ",%" r0)))))
448 (define (i386:shl-r info n)
449 (let ((r (get-r info)))
450 `((,(string-append "shl____$i8,%" r) (#:immediate1 ,n)))))
452 (define (i386:r+r info)
453 (let ((r (get-r info)))
454 `((,(string-append "add____%" r ",%" r)))))
456 (define (i386:not-r info)
457 (let ((r (get-r info)))
458 `((,(string-append "not____%" r)))))
460 (define (i386:r0-xor-r1 info)
461 (let ((r0 (get-r0 info))
463 `((,(string-append "xor____%" r1 ",%" r0)))))
465 (define (i386:r0-mem->r1-mem info)
466 (let* ((registers (.registers info))
469 (r2 (car registers)))
470 `((,(string-append "mov____(%" r0 "),%" r2))
471 (,(string-append "mov____%" r2 ",(%" r1 ")")))))
473 (define (i386:byte-r0-mem->r1-mem info)
474 (let* ((registers (.registers info))
479 `((,(string-append "mov____(%" r0 "),%" l2))
480 (,(string-append "mov____%" l2 ",(%" r1 ")")))))
482 (define (i386:word-r0-mem->r1-mem info)
483 (let* ((registers (.registers info))
488 `((,(string-append "mov____(%" r0 "),%" x2))
489 (,(string-append "mov____%" x2 ",(%" r1 ")")))))
491 (define (i386:r0+value info v)
492 (let ((r0 (get-r0 info)))
493 `(,(if (< (abs v) #x80) `(,(string-append "add____$i8,%" r0) (#:immediate1 ,v))
494 `(,(string-append "add____$i32,%" r0) (#:immediate ,v))))))
496 (define (i386:value->r0 info v)
497 (let ((r0 (get-r0 info)))
498 `((,(string-append "mov____$i32,%" r0) (#:immediate ,v)))))
500 (define (i386:byte-r->local+n info id n)
501 (let* ((n (+ (- 0 (* 4 id)) n))
504 `(,(if (< (abs n) #x80) `(,(string-append "mov____%" l ",0x8(%ebp)") (#:immediate1 ,n))
505 `(,(string-append "mov____%" l ",0x32(%ebp)") (#:immediate ,n))))))
507 (define (i386:word-r->local+n info id n)
508 (let* ((n (+ (- 0 (* 4 id)) n))
511 `(,(if (< (abs n) #x80) `(,(string-append "mov____%" x ",0x8(%ebp)") (#:immediate1 ,n))
512 `(,(string-append "mov____%" x ",0x32(%ebp)") (#:immediate ,n))))))
514 (define (i386:r-and info v)
515 (let ((r (get-r info)))
516 `((,(string-append "and____$i32,%" r) (#:immediate ,v)))))
518 (define (i386:push-r0 info)
519 (let ((r0 (get-r0 info)))
520 `((,(string-append "push___%" r0)))))
522 (define (i386:r1->r0 info)
523 (let ((r0 (get-r0 info))
525 `((,(string-append "mov____%" r1 ",%" r0)))))
527 (define (i386:pop-r0 info)
528 (let ((r0 (get-r0 info)))
529 `((,(string-append "pop____%" r0)))))
531 (define (i386:swap-r-stack info)
532 (let ((r (get-r info)))
533 `((,(string-append "xchg___%" r ",(%esp)")))))
535 (define (i386:swap-r1-stack info)
536 (let ((r0 (get-r0 info)))
537 `((,(string-append "xchg___%" r0 ",(%esp)")))))
539 (define (i386:r2->r0 info)
540 (let ((r0 (get-r0 info))
541 (allocated (.allocated info)))
542 (if (> (length allocated) 2)
543 (let ((r2 (cadddr allocated)))
544 `((,(string-append "mov____%" r2 ",%" r1))))
545 `((,(string-append "pop____%" r0))
546 (,(string-append "push___%" r0))))))
548 (define i386:instructions
550 (a?->r . ,i386:a?->r)
551 (ae?->r . ,i386:ae?->r)
552 (b?->r . ,i386:b?->r)
553 (be?->r . ,i386:be?->r)
554 (byte-mem->r . ,i386:byte-mem->r)
555 (byte-r . ,i386:byte-r)
556 (byte-r->local+n . ,i386:byte-r->local+n)
557 (byte-r0->r1-mem . ,i386:byte-r0->r1-mem)
558 (byte-r0->r1-mem . ,i386:byte-r0->r1-mem)
559 (byte-r0-mem->r1-mem . ,i386:byte-r0-mem->r1-mem)
560 (byte-signed-r . ,i386:byte-signed-r)
561 (call-label . ,i386:call-label)
562 (call-r . ,i386:call-r)
563 (function-locals . ,i386:function-locals)
564 (function-preamble . ,i386:function-preamble)
565 (g?->r . ,i386:g?->r)
566 (ge?->r . ,i386:ge?->r)
568 (jump-a . ,i386:jump-a)
569 (jump-ae . ,i386:jump-ae)
570 (jump-b . ,i386:jump-b)
571 (jump-be . ,i386:jump-be)
572 (jump-byte-z . ,i386:jump-byte-z)
573 (jump-g . , i386:jump-g)
574 (jump-ge . , i386:jump-ge)
575 (jump-l . ,i386:jump-l)
576 (jump-le . ,i386:jump-le)
577 (jump-nz . ,i386:jump-nz)
578 (jump-z . ,i386:jump-z)
579 (l?->r . ,i386:l?->r)
580 (label->arg . ,i386:label->arg)
581 (label->r . ,i386:label->r)
582 (label-mem->r . ,i386:label-mem->r)
583 (label-mem-add . ,i386:label-mem-add)
584 (le?->r . ,i386:le?->r)
585 (local->r . ,i386:local->r)
586 (local-add . ,i386:local-add)
587 (local-ptr->r . ,i386:local-ptr->r)
588 (long-r0->r1-mem . ,i386:r0->r1-mem)
589 (long-r0-mem->r1-mem . ,i386:r0-mem->r1-mem)
590 (mem->r . ,i386:mem->r)
592 (not-r . ,i386:not-r)
593 (pop-r0 . ,i386:pop-r0)
594 (pop-register . ,i386:pop-register)
595 (push-r0 . ,i386:push-r0)
596 (push-register . ,i386:push-register)
598 (r+value . ,i386:r+value)
599 (r->arg . ,i386:r->arg)
600 (r->byte-label . ,i386:r->byte-label)
601 (r->label . ,i386:r->label)
602 (r->local . ,i386:r->local)
603 (r->local+n . ,i386:r->local+n)
604 (r->word-label . ,i386:r->word-label)
605 (r-and . ,i386:r-and)
606 (r-byte-mem-add . ,i386:r-byte-mem-add)
607 (r-cmp-value . ,i386:r-cmp-value)
608 (r-mem-add . ,i386:r-mem-add)
609 (r-negate . ,i386:r-negate)
610 (r-word-mem-add . ,i386:r-word-mem-add)
611 (r-zero? . ,i386:r-zero?)
612 (r0%r1 . ,i386:r0%r1)
613 (r0*r1 . ,i386:r0*r1)
614 (r0+r1 . ,i386:r0+r1)
615 (r0+value . ,i386:r0+value)
616 (r0->r1 . ,i386:r0->r1)
617 (r0->r1-mem . ,i386:r0->r1-mem)
618 (r0-and-r1 . ,i386:r0-and-r1)
619 (r0-mem->r1-mem . ,i386:r0-mem->r1-mem)
620 (r0-or-r1 . ,i386:r0-or-r1)
621 (r0-r1 . ,i386:r0-r1)
622 (r0-xor-r1 . ,i386:r0-xor-r1)
623 (r0/r1 . ,i386:r0/r1)
624 (r0<<r1 . ,i386:r0<<r1)
625 (r0>>r1 . ,i386:r0>>r1)
626 (r1->r0 . ,i386:r1->r0)
627 (r2->r0 . ,i386:r2->r0)
629 (return->r . ,i386:return->r)
630 (shl-r . ,i386:shl-r)
631 (swap-r-stack . ,i386:swap-r-stack)
632 (swap-r0-r1 . ,i386:swap-r0-r1)
633 (swap-r1-stack . ,i386:swap-r1-stack)
634 (test-r . ,i386:test-r)
635 (value->r . ,i386:value->r)
636 (value->r0 . ,i386:value->r0)
637 (word-mem->r . ,i386:word-mem->r)
638 (word-r . ,i386:word-r)
639 (word-r->local+n . ,i386:word-r->local+n)
640 (word-r0->r1-mem . ,i386:word-r0->r1-mem)
641 (word-r0-mem->r1-mem . ,i386:word-r0-mem->r1-mem)
642 (word-signed-r . ,i386:word-signed-r)
643 (xor-zf . ,i386:xor-zf)
644 (zf->r . ,i386:zf->r)