1 ;;;============================================================================
5 ;;; Copyright (c) 2010-2012 by Marc Feeley, All Rights Reserved.
7 ;;;============================================================================
9 ;;; This module implements the x86 instruction encoding.
11 (namespace ("_x86#") ("" include))
12 (include "~~lib/gambit#.scm")
14 (include "_assert#.scm")
17 (include "_codegen#.scm")
21 ;;;============================================================================
23 ;;; Architecture selection (either x86-32 or x86-64).
25 (define (x86-arch-set! cgc arch)
26 (codegen-context-arch-set! cgc arch)
27 (if (codegen-context-listing-format cgc)
30 (case (codegen-context-listing-format cgc)
32 (list #\tab ".code" (x86-word-width cgc)))
34 (list #\tab "bits " (x86-word-width cgc)))))))
36 (define (x86-64bit-mode? cgc)
37 (eq? (codegen-context-arch cgc) 'x86-64))
39 (define (x86-word-width cgc)
40 (if (x86-64bit-mode? cgc) 64 32))
42 (define-macro (x86-assert-64bit-mode cgc)
43 `(assert (x86-64bit-mode? ,cgc)
44 "instruction only valid for x86-64"))
46 (define-macro (x86-assert-32bit-mode cgc)
47 `(assert (not (x86-64bit-mode? ,cgc))
48 "instruction only valid for x86-32"))
50 ;;;----------------------------------------------------------------------------
52 ;;; Instruction operands.
54 (define (x86-force-width opnd width)
55 ;; useful for formatting to get an operand with an explicit width
56 (vector opnd width 'dummy))
58 (define (x86-force-width? x) (and (vector? x) (fx= (vector-length x) 3)))
59 (define (x86-force-width-opnd x) (vector-ref x 0))
60 (define (x86-force-width-width x) (vector-ref x 1))
62 (define (x86-imm? x) (pair? x))
64 (define (x86-imm-int value #!optional (width 32)) (cons width value))
65 (define (x86-imm-int? x) (and (pair? x) (number? (cdr x))))
66 (define (x86-imm-int-width x) (car x))
67 (define (x86-imm-int-value x) (cdr x))
69 (define (x86-imm-lbl label #!optional (offset 0)) (cons offset label))
70 (define (x86-imm-lbl? x) (and (pair? x) (vector? (cdr x))))
71 (define (x86-imm-lbl-offset x) (car x))
72 (define (x86-imm-lbl-label x) (cdr x))
74 (define (x86-imm-late handler width) (cons width handler))
75 (define (x86-imm-late? x) (and (pair? x) (procedure? (cdr x))))
76 (define (x86-imm-late-width x) (car x))
77 (define (x86-imm-late-handler x) (cdr x))
79 ;;(define (x86-glo name #!optional (offset 0))
80 ;; (vector name offset))
82 ;;(define (x86-glo? x) (and (vector? x) (fx= (vector-length x) 2)))
83 ;;(define (x86-glo-name x) (vector-ref x 0))
84 ;;(define (x86-glo-offset x) (vector-ref x 1))
86 (define (x86-mem offset #!optional (reg1 #f) (reg2 #f) (scale 0))
87 (vector offset reg1 reg2 scale))
89 (define (x86-mem? x) (and (vector? x) (fx= (vector-length x) 4)))
90 (define (x86-mem-offset x) (vector-ref x 0))
91 (define (x86-mem-reg1 x) (vector-ref x 1))
92 (define (x86-mem-reg2 x) (vector-ref x 2))
93 (define (x86-mem-scale x) (vector-ref x 3))
95 (define (x86-mem-abs? x)
96 (and (not (x86-mem-reg1 x))
97 (not (x86-mem-reg2 x))))
99 ;;;----------------------------------------------------------------------------
101 ;;; Listing generation.
103 (define (x86-offset->string offset)
104 (cond ((fx= offset 0) "")
105 ((fx< offset 0) (number->string offset))
106 (else (string-append "+" (number->string offset)))))
108 (define (x86-listing cgc mnemonic width . opnds)
110 (define (instr-format-gnu)
112 (define (opnd-format opnd)
113 (cond ((x86-force-width? opnd)
114 (opnd-format (x86-force-width-opnd opnd)))
116 (list "%" (x86-register-name opnd)))
119 (cond ((x86-imm-int? opnd)
120 (x86-imm-int-value opnd))
122 (list (asm-label-name (x86-imm-lbl-label opnd))
123 (x86-offset->string (x86-imm-lbl-offset opnd))))
124 ((x86-imm-late? opnd)
125 ((x86-imm-late-handler opnd) cgc 'listing))
127 (error "unknown immediate" opnd)))))
129 ((x86-glo? opnd);;;;;;;;;;
130 (let ((name (x86-glo-name opnd))
131 (offset (x86-glo-offset opnd)))
133 (x86-offset->string offset))))
135 (let ((reg1 (x86-mem-reg1 opnd))
136 (reg2 (x86-mem-reg2 opnd))
137 (scale (x86-mem-scale opnd))
138 (offset (x86-mem-offset opnd)))
142 (cons (opnd-format reg1)
145 (cons (opnd-format reg2)
149 (fxarithmetic-shift-left
154 (if (fx= offset 0) x (cons offset x)))
160 (asm-separated-list (map opnd-format (reverse opnds)) ",")))
164 (cons (x86-width-suffix cgc width)
175 (define (instr-format-nasm)
177 (define (data-width-qualifier width)
183 ((1) "short ") ;; special width for short jumps
186 (define (opnd-format opnd)
187 (cond ((x86-force-width? opnd)
188 (list (data-width-qualifier (x86-force-width-width opnd))
189 (opnd-format (x86-force-width-opnd opnd))))
191 (x86-register-name opnd))
193 (cond ((x86-imm-int? opnd)
194 (let ((value (x86-imm-int-value opnd))
195 (opnd-width (x86-imm-int-width opnd)))
196 (if (or (fx= width 8)
197 (fx= width opnd-width)
200 (not (equal? mnemonic "mov"))))
202 (list (data-width-qualifier opnd-width) value))))
204 (list (asm-label-name (x86-imm-lbl-label opnd))
205 (x86-offset->string (x86-imm-lbl-offset opnd))))
206 ((x86-imm-late? opnd)
207 ((x86-imm-late-handler opnd) cgc 'listing))
209 (error "unknown immediate" opnd))))
211 ((x86-glo? opnd);;;;;;;;;;
212 (let ((name (x86-glo-name opnd))
213 (offset (x86-glo-offset opnd)))
216 (x86-offset->string offset)
219 (let ((offset (x86-mem-offset opnd))
220 (reg1 (x86-mem-reg1 opnd))
221 (reg2 (x86-mem-reg2 opnd))
222 (scale (x86-mem-scale opnd)))
233 (fxarithmetic-shift-left 1 scale))))
235 (x86-offset->string offset)
243 (let ((width-implicit? #f))
245 (define (opnd-fmt opnd)
247 (set! width-implicit? #t))
251 (asm-separated-list (map opnd-fmt opnds) ",")))
255 (cons (data-width-qualifier width)
261 (case (codegen-context-listing-format cgc)
265 (instr-format-nasm)))))
267 (define (x86-width-suffix cgc width)
268 (case (codegen-context-listing-format cgc)
270 (cond ((fx= width 64) "q")
279 (define (x86-xmm-width-suffix cgc width)
280 (case (codegen-context-listing-format cgc)
282 (cond ((fx= width 64) "d")
289 (define (x86-esc-opcode cgc)
292 ;;;----------------------------------------------------------------------------
294 ;;; X86 operand encoding.
296 (define (x86-opnd-prefix-reg-opnd cgc reg opnd)
304 (not (x86-reg8-h? reg)))))
308 (x86-reg-field opnd))
310 (and (fx= (x86-reg-width opnd) 8)
312 (not (x86-reg8-h? opnd))))
318 (or ext-lo8-reg? ext-lo8-reg2?))))
319 (assert (not (and rex?
320 (or (x86-reg8-h? reg)
321 (x86-reg8-h? opnd))))
322 "cannot use high 8 bit register here" reg opnd)
330 (define (x86-opnd-prefix-opnd cgc width opnd)
333 (x86-reg-field opnd))
337 (not (x86-reg8-h? opnd)))))
338 (x86-opnd-prefix cgc width 0 opnd ext-lo8-reg?))
339 (x86-opnd-prefix cgc width 0 opnd #f)))
341 (define (x86-opnd-modrm/sib-reg-opnd cgc reg opnd)
342 (x86-opnd-modrm/sib cgc (x86-reg-field reg) opnd))
344 (define (x86-opnd-prefix cgc width field opnd force-rex?)
346 (fx+ ;; if needed emit REX.W (64 bit operand size)
347 (if (and (not (fx= width 0)) ;; implicit width?
349 (and (x86-reg? opnd) (x86-reg64? opnd))))
352 ;; if needed emit REX.R (Extension of the ModR/M reg field)
353 (fxarithmetic-shift-left
354 (fxarithmetic-shift-right
358 (cond ((x86-reg? opnd)
359 ;; if needed emit REX.B (Extension of
360 ;; the ModR/M r/m field, SIB base field,
361 ;; or Opcode reg field)
362 (fxarithmetic-shift-right
366 ((x86-glo? opnd);;;;;;;;;;
369 (let ((reg1 (x86-mem-reg1 opnd)))
372 (assert (or (x86-reg32? reg1)
373 (and (x86-reg64? reg1)
374 (x86-64bit-mode? cgc)))
375 "invalid width base register" reg1)
376 (fx+ ;; if needed emit REX.B (Extension of
377 ;; the ModR/M r/m field, SIB base field,
378 ;; or Opcode reg field)
379 (fxarithmetic-shift-right
382 (let ((reg2 (x86-mem-reg2 opnd)))
385 (assert (if (x86-reg32? reg1)
388 "index register must have same width as base" reg2)
389 ;; if needed emit REX.X (Extension
390 ;; of the SIB index field)
391 (fxarithmetic-shift-left
392 (fxarithmetic-shift-right
399 (error "unknown operand" opnd))))))
400 (x86-opnd-size-override-prefix cgc width)
401 (x86-addr-size-override-prefix cgc opnd)
405 (x86-assert-64bit-mode cgc)
406 (asm-8 cgc (fx+ #x40 rex*)) ;; REX
410 (define (x86-opnd-size-override-prefix cgc width)
412 (asm-8 cgc #x66))) ;; operand size override prefix
414 (define (x86-addr-size-override-prefix cgc opnd)
415 (if (and (x86-mem? opnd)
416 (let ((reg1 (x86-mem-reg1 opnd)))
418 (eq? (x86-64bit-mode? cgc)
419 (not (x86-reg64? reg1))))))
420 (asm-8 cgc #x67))) ;; address size override prefix
422 (define (x86-abs-addr cgc label offset width)
424 (assert (fx= width 32)
425 "x86-abs-addr expects width=32" width)
427 (let ((lbl (asm-make-label cgc 'fixup)))
429 (codegen-context-fixup-list-set!
432 (codegen-context-fixup-list cgc)))
442 (asm-32-le cgc (fx+ (asm-label-pos label) offset))))))
444 (define (x86-opnd-modrm/sib cgc field opnd)
446 (fxarithmetic-shift-left (fxand 7 field) 3)))
449 (if (x86-64bit-mode? cgc) ;; avoid RIP relative encoding?
451 (asm-8 cgc (fx+ modrm-rf 4)) ;; ModR/M
452 (asm-8 cgc #x25)) ;; SIB
453 (asm-8 cgc (fx+ modrm-rf 5)))) ;; ModR/M
455 (cond ((x86-reg? opnd)
457 (fx+ modrm-rf (fxand 7 (x86-reg-field opnd)))))
458 (asm-8 cgc (fx+ #xc0 modrm*)))) ;; ModR/M
461 ((x86-glo? opnd);;;;;;;;;;
463 (let ((name (x86-glo-name opnd))
464 (offset (x86-glo-offset opnd)))
465 (x86-abs-addr cgc (nat-global-lookup cgc name) offset 32)))
468 (let ((offset (x86-mem-offset opnd))
469 (reg1 (x86-mem-reg1 opnd)))
473 (let* ((field1 (x86-reg-field reg1))
474 (field1-lo (fxand 7 field1))
475 (reg2 (x86-mem-reg2 opnd)))
477 (if (or reg2 ;; need a SIB when using an index
478 (fx= field1-lo 4)) ;; register or base = RSP/R12
487 (let ((field2 (x86-reg-field reg2)))
488 (assert (not (fx= field2 4))
489 "SP not allowed as index" reg2)
490 (fx+ (fxarithmetic-shift-left
493 (fxarithmetic-shift-left
496 #x20)))) ;; no index and no scaling
498 (if (asm-signed8? offset)
499 (if (or (not (fx= offset 0)) ;; non-null offset?
500 (fx= field1 5)) ;; or RBP
501 (begin ;; use 8 bit displacement
502 (asm-8 cgc (fx+ #x40 modrm*)) ;; ModR/M
503 (asm-8 cgc sib) ;; SIB
506 (asm-8 cgc (fx+ #x00 modrm*)) ;; ModR/M
507 (asm-8 cgc sib))) ;; SIB
508 (begin ;; use 32 bit displacement
509 (asm-8 cgc (fx+ #x80 modrm*)) ;; ModR/M
510 (asm-8 cgc sib) ;; SIB
511 (asm-32-le cgc offset))))
516 (fx+ modrm-rf field1-lo)))
517 (if (asm-signed8? offset)
518 (if (or (not (fx= offset 0)) ;; non-null offset?
519 (fx= field1-lo 5)) ;; or RBP/R13
520 (begin ;; use 8 bit displacement
521 (asm-8 cgc (fx+ #x40 modrm*)) ;; ModR/M
523 (asm-8 cgc (fx+ #x00 modrm*))) ;; ModR/M
524 (begin ;; use 32 bit displacement
525 (asm-8 cgc (fx+ #x80 modrm*)) ;; ModR/M
526 (asm-32-le cgc offset))))))
528 (begin ;; absolute address, use disp32 ModR/M
530 (asm-32-le cgc offset)))))
533 (error "unknown operand" opnd)))))
535 (define (x86-imm-encode cgc imm imm-width)
536 (cond ((x86-imm-int? imm)
537 (let* ((n1 (x86-imm-int-value imm))
538 (n2 (asm-int-le cgc n1 imm-width)))
540 "immediate operand has been truncated" n1 imm-width)
541 (x86-imm-int n2 imm-width)))
543 (x86-imm-lbl-encode cgc imm imm-width)
546 ((x86-imm-late-handler imm) cgc 'encode))
548 (error "unknown immediate"))))
550 (define (x86-imm-lbl-encode cgc imm-lbl imm-width)
551 (let ((lbl (asm-make-label cgc 'fixup)))
552 (codegen-context-fixup-list-set!
554 (cons (cons lbl imm-width)
555 (codegen-context-fixup-list cgc)))
562 (fxarithmetic-shift-right imm-width 3))
566 (fx+ (asm-label-pos (x86-imm-lbl-label imm-lbl))
567 (x86-imm-lbl-offset imm-lbl))))
568 (asm-int-le cb dist imm-width))))))
570 ;;;----------------------------------------------------------------------------
572 ;;; X86 pseudo operations.
574 (define (x86-label cgc label)
575 (asm-label cgc label)
576 (if (codegen-context-listing-format cgc)
577 (asm-listing cgc (list (asm-label-name label) ":"))))
579 (define (x86-db cgc . elems)
580 (x86-data-elems cgc elems 8))
582 (define (x86-dw cgc . elems)
583 (x86-data-elems cgc elems 16))
585 (define (x86-dd cgc . elems)
586 (x86-data-elems cgc elems 32))
588 (define (x86-dq cgc . elems)
589 (x86-data-elems cgc elems 64))
591 (define (x86-data-elems cgc elems width)
593 (define max-per-line 4)
595 (let ((v (list->vector elems)))
597 (if (fx< i (vector-length v))
598 (let ((lim (fxmin (fx+ i max-per-line) (vector-length v))))
599 (let loop2 ((j i) (rev-lst '()))
601 (let ((x (vector-ref v j)))
602 (asm-int-le cgc x width)
603 (loop2 (fx+ j 1) (cons x rev-lst)))
605 (if (codegen-context-listing-format cgc)
609 (case (codegen-context-listing-format cgc)
611 (cond ((fx= width 8) ".byte")
612 ((fx= width 16) ".word")
613 ((fx= width 32) ".long")
614 ((fx= width 64) ".quad")
615 (else (error "unknown data width"))))
617 (cond ((fx= width 8) "db")
618 ((fx= width 16) "dw")
619 ((fx= width 32) "dd")
620 ((fx= width 64) "dq")
621 (else (error "unknown data width")))))
623 (asm-separated-list (reverse rev-lst) ","))))
626 ;;;----------------------------------------------------------------------------
628 ;;; X86 instructions: ADD, OR, ADC, SBB, AND, SUB, XOR, CMP, and MOV.
630 (define (x86-add cgc opnd1 opnd2 #!optional (width #f))
631 (x86-op cgc opnd1 opnd2 width 0))
633 (define (x86-or cgc opnd1 opnd2 #!optional (width #f))
634 (x86-op cgc opnd1 opnd2 width 1))
636 (define (x86-adc cgc opnd1 opnd2 #!optional (width #f))
637 (x86-op cgc opnd1 opnd2 width 2))
639 (define (x86-sbb cgc opnd1 opnd2 #!optional (width #f))
640 (x86-op cgc opnd1 opnd2 width 3))
642 (define (x86-and cgc opnd1 opnd2 #!optional (width #f))
643 (x86-op cgc opnd1 opnd2 width 4))
645 (define (x86-sub cgc opnd1 opnd2 #!optional (width #f))
646 (x86-op cgc opnd1 opnd2 width 5))
648 (define (x86-xor cgc opnd1 opnd2 #!optional (width #f))
649 (x86-op cgc opnd1 opnd2 width 6))
651 (define (x86-cmp cgc opnd1 opnd2 #!optional (width #f))
652 (x86-op cgc opnd1 opnd2 width 7))
654 (define (x86-mov cgc opnd1 opnd2 #!optional (width #f))
655 (x86-op cgc opnd1 opnd2 width 17))
657 (define (x86-op cgc opnd1 opnd2 width op)
659 ;; opnd1 = destination, opnd2 = source
661 (define (listing width opnd1 opnd2)
662 (if (codegen-context-listing-format cgc)
666 '#("add" "or" "adc" "sbb" "and" "sub" "xor" "cmp")
675 (define (register-mov-imm width)
676 (x86-opnd-prefix-opnd cgc width opnd1) ;; prefix
677 ;; opcode = #xb0-#xb7 (for 8 bit registers)
678 ;; or #xb8-#xbf (for 16/32/64 bit registers)
679 (asm-8 cgc (fx+ (if (fx= width 8) #xb0 #xb8) ;; opcode
680 (fxand 7 (x86-reg-field opnd1))))
683 (x86-imm-encode cgc opnd2 width)))
685 (define (general-mov-imm width imm-width)
686 (x86-opnd-prefix-opnd cgc width opnd1) ;; prefix
687 (asm-8 cgc (if (fx= width 8) #xc6 #xc7)) ;; opcode
688 (x86-opnd-modrm/sib cgc 0 opnd1) ;; ModR/M
691 (x86-imm-encode cgc opnd2 imm-width)))
693 (assert (if (x86-reg? opnd1)
695 (fx= (x86-reg-width opnd1) width))
697 "missing or inconsistent operand width" width)
699 (assert (or (x86-reg? opnd1)
701 (and (x86-imm-int? opnd2)
702 (asm-signed32? (x86-imm-int-value opnd2))))
703 "move of a 64 bit immediate only possible with register")
706 (let ((width (x86-reg-width opnd1)))
707 (if (and (fx= width 64)
709 (asm-signed32? (x86-imm-int-value opnd2)))
710 (general-mov-imm width 32)
711 (register-mov-imm width)))
712 (general-mov-imm width (fxmin width 32))))
716 (define (accumulator-op-imm width)
717 (x86-opnd-prefix-opnd cgc width opnd1) ;; prefix
718 ;; opcode = #x04, #x0c, #x14, ..., #x3c (for AL)
719 ;; or #x05, #x0d, #x15, ..., #x3d (for AX/EAX/RAX)
720 (asm-8 cgc (fx+ (if (fx= width 8) #x04 #x05) ;; opcode
721 (fxarithmetic-shift-left op 3)))
724 (x86-imm-encode cgc opnd2 (fxmin 32 width))))
726 (define (general-op-imm width)
727 (x86-opnd-prefix-opnd cgc width opnd1) ;; prefix
729 (asm-8 cgc #x80) ;; opcode = 8 bit operation
730 (x86-opnd-modrm/sib cgc op opnd1) ;; ModR/M
733 (x86-imm-encode cgc opnd2 8)))
734 ((and (x86-imm-int? opnd2)
735 (asm-signed8? (x86-imm-int-value opnd2)))
736 (asm-8 cgc #x83) ;; opcode = sign extended 8 bit imm
737 (x86-opnd-modrm/sib cgc op opnd1) ;; ModR/M
740 (x86-imm-encode cgc opnd2 8)))
742 (asm-8 cgc #x81) ;; opcode = sign extended 16/32 bit imm
743 (x86-opnd-modrm/sib cgc op opnd1) ;; ModR/M
746 (x86-imm-encode cgc opnd2 (fxmin 32 width))))))
748 (assert (if (x86-reg? opnd1)
750 (fx= (x86-reg-width opnd1) width))
752 "missing or inconsistent operand width" width)
755 (let ((width (x86-reg-width opnd1))
756 (field (x86-reg-field opnd1)))
757 (if (and (fx= field 0)
759 (not (x86-imm-int? opnd2))
760 (not (asm-signed8? (x86-imm-int-value opnd2)))))
761 (accumulator-op-imm width)
762 (general-op-imm width)))
763 (general-op-imm width)))
765 (define (reg-op reg opnd swapped?)
767 (assert (or (not width)
768 (fx= (x86-reg-width reg) width))
769 "inconsistent operand width" width)
771 (x86-opnd-prefix-reg-opnd cgc reg opnd) ;; prefix
773 (if (and (and #f ;; comment-out for consistency with system assembler
774 (not (x86-64bit-mode? cgc)))
776 (fx= (x86-reg-field reg) 0) ;; accumulator?
777 (x86-mem? opnd) ;; absolute address
780 ;; opcode = #xa0/#xa2 (for 8 bit registers)
781 ;; or #xa1/#xa3 (for 16/32/64 bit registers)
782 (asm-8 cgc (fx+ (if swapped? #xa2 #xa0) ;; opcode
783 (if (x86-reg8? reg) 0 1)))
784 (asm-32-le cgc (x86-mem-offset opnd)))
786 (asm-8 cgc (fx+ (fxarithmetic-shift-left op 3) ;; opcode
788 (if (x86-reg8? reg) 0 1)))
789 (x86-opnd-modrm/sib-reg-opnd cgc reg opnd))) ;; ModR/M
791 (listing (x86-reg-width reg)
792 (if swapped? opnd reg)
793 (if swapped? reg opnd)))
795 (cond ((x86-imm? opnd2)
796 (if (fx= op 17) ;; move?
800 (reg-op opnd2 opnd1 #t))
802 (reg-op opnd1 opnd2 #f))
804 (error "invalid operand combination" opnd1 opnd2))))
806 ;;;----------------------------------------------------------------------------
808 ;;; X86 instructions: INC and DEC.
810 (define (x86-inc cgc opnd #!optional (width #f))
811 (x86-inc-dec cgc opnd width #x40))
813 (define (x86-dec cgc opnd #!optional (width #f))
814 (x86-inc-dec cgc opnd width #x48))
816 (define (x86-inc-dec cgc opnd width op)
818 ;; opnd = destination
820 (define (listing width)
821 (if (codegen-context-listing-format cgc)
823 (if (fx= op #x40) "inc" "dec")
827 (define (register width)
828 (x86-opnd-prefix-opnd cgc width opnd) ;; prefix
829 (let ((field (x86-reg-field opnd)))
830 (asm-8 cgc (fx+ op field))) ;; opcode
833 (define (general width)
834 (x86-opnd-prefix-opnd cgc width opnd) ;; prefix
835 (asm-8 cgc (if (fx= width 8) #xfe #xff)) ;; opcode
836 (x86-opnd-modrm/sib cgc (if (fx= op #x40) 0 1) opnd) ;; ModR/M
839 (assert (if (x86-reg? opnd)
841 (fx= (x86-reg-width opnd) width))
843 "missing or inconsistent operand width" width)
846 (let ((width (x86-reg-width opnd)))
847 (if (and (not (x86-64bit-mode? cgc))
854 ;;;----------------------------------------------------------------------------
856 ;;; X86 instruction: LEA.
858 (define (x86-lea cgc reg opnd)
860 ;; reg = destination, opnd = source
862 (assert (not (x86-reg8? reg))
863 "destination of lea must not be an 8 bit register" reg)
865 (x86-opnd-prefix-reg-opnd cgc reg opnd) ;; prefix
866 (asm-8 cgc #x8d) ;; opcode
867 (x86-opnd-modrm/sib-reg-opnd cgc reg opnd) ;; ModR/M
869 (if (codegen-context-listing-format cgc)
876 ;;;----------------------------------------------------------------------------
878 ;;; X86 instruction: RET.
880 (define (x86-ret cgc #!optional (n 0))
883 (asm-8 cgc #xc3) ;; opcode
884 (if (codegen-context-listing-format cgc)
889 (asm-8 cgc #xc2) ;; opcode
891 (if (codegen-context-listing-format cgc)
895 (x86-imm-int n 0))))))
897 ;;;----------------------------------------------------------------------------
899 ;;; X86 instruction: ENTER.
901 (define (x86-enter cgc size level)
902 (let* ((size-opnd (x86-imm-int size 16))
903 (level-opnd (x86-imm-int level 8)))
904 (asm-8 cgc #xc8) ;; opcode
905 (x86-imm-encode cgc size-opnd 16)
906 (x86-imm-encode cgc level-opnd 8)
908 (if (codegen-context-listing-format cgc)
909 (case (codegen-context-listing-format cgc)
920 (number->string size)
921 (number->string level)))))))
923 ;;;----------------------------------------------------------------------------
925 ;;; X86 instructions: NOP, LEAVE, HLT, CMC, CLC, STC, CLI, STI, CLD, and STD.
927 (define (x86-nop cgc) (x86-no-opnd-instr cgc #x90))
928 (define (x86-leave cgc) (x86-no-opnd-instr cgc #xc9))
929 (define (x86-hlt cgc) (x86-no-opnd-instr cgc #xf4))
930 (define (x86-cmc cgc) (x86-no-opnd-instr cgc #xf5))
931 (define (x86-clc cgc) (x86-no-opnd-instr cgc #xf8))
932 (define (x86-stc cgc) (x86-no-opnd-instr cgc #xf9))
933 (define (x86-cli cgc) (x86-no-opnd-instr cgc #xfa))
934 (define (x86-sti cgc) (x86-no-opnd-instr cgc #xfb))
935 (define (x86-cld cgc) (x86-no-opnd-instr cgc #xfc))
936 (define (x86-std cgc) (x86-no-opnd-instr cgc #xfd))
938 (define (x86-no-opnd-instr cgc opcode)
940 (asm-8 cgc opcode) ;; opcode
942 (if (codegen-context-listing-format cgc)
944 (cond ((fx= opcode #x90)
950 '#("hlt" "cmc" "???" "???" "clc" "stc"
951 "cli" "sti" "cld" "std")
955 ;;;----------------------------------------------------------------------------
957 ;;; X86 instructions: SYSCALL, SYSRET, WRMSR, RDTSC, RDMSR, RDPMC,
960 (define (x86-syscall cgc) (x86-no-opnd-instr-esc cgc #x05))
961 (define (x86-sysret cgc) (x86-no-opnd-instr-esc cgc #x07))
962 (define (x86-wrmsr cgc) (x86-no-opnd-instr-esc cgc #x30))
963 (define (x86-rdtsc cgc) (x86-no-opnd-instr-esc cgc #x31))
964 (define (x86-rdmsr cgc) (x86-no-opnd-instr-esc cgc #x32))
965 (define (x86-rdpmc cgc) (x86-no-opnd-instr-esc cgc #x33))
966 (define (x86-cpuid cgc) (x86-no-opnd-instr-esc cgc #xa2))
968 (define (x86-no-opnd-instr-esc cgc opcode)
970 (x86-esc-opcode cgc) ;; escape opcode
971 (asm-8 cgc opcode) ;; opcode
973 (if (codegen-context-listing-format cgc)
975 (cond ((fx= opcode #x05)
981 (else ;; (fx<= opcode #x33)
983 '#("wrmsr" "rdtsc" "rdmsr" "rdpmc")
987 ;;;----------------------------------------------------------------------------
989 ;;; X86 instructions: JMP, CALL, JO, JNO, JB, JAE, JE, JNE, JBE, JA,
990 ;;; JS, JNS, JP, JNP, JL, JGE, JLE, and JG.
992 ;; Unconditional jump/call opcodes
994 (define x86-jmp-rel8-opcode #xeb)
995 (define x86-jmp-rel32-opcode #xe9)
996 (define x86-call-rel32-opcode #xe8)
998 ;; Conditional jump opcodes (for the rel32 kind, add #x10 with #x0f opcode)
1000 (define x86-jo-rel8-opcode #x70)
1001 (define x86-jno-rel8-opcode #x71)
1002 (define x86-jb-rel8-opcode #x72)
1003 ;;(define x86-jnae-rel8-opcode x86-jb-rel8-opcode)
1004 ;;(define x86-jc-rel8-opcode x86-jb-rel8-opcode)
1005 (define x86-jae-rel8-opcode #x73)
1006 ;;(define x86-jnb-rel8-opcode x86-jae-rel8-opcode)
1007 ;;(define x86-jnc-rel8-opcode x86-jae-rel8-opcode)
1008 (define x86-je-rel8-opcode #x74)
1009 ;;(define x86-jz-rel8-opcode x86-je-rel8-opcode)
1010 (define x86-jne-rel8-opcode #x75)
1011 ;;(define x86-jnz-rel8-opcode x86-jne-rel8-opcode)
1012 (define x86-jbe-rel8-opcode #x76)
1013 ;;(define x86-jna-rel8-opcode x86-jbe-rel8-opcode)
1014 (define x86-ja-rel8-opcode #x77)
1015 ;;(define x86-jnbe-rel8-opcode x86-ja-rel8-opcode)
1016 (define x86-js-rel8-opcode #x78)
1017 (define x86-jns-rel8-opcode #x79)
1018 (define x86-jp-rel8-opcode #x7a)
1019 ;;(define x86-jpe-rel8-opcode x86-jp-rel8-opcode)
1020 (define x86-jnp-rel8-opcode #x7b)
1021 ;;(define x86-jpo-rel8-opcode x86-jnp-rel8-opcode)
1022 (define x86-jl-rel8-opcode #x7c)
1023 ;;(define x86-jnge-rel8-opcode x86-jl-rel8-opcode)
1024 (define x86-jge-rel8-opcode #x7d)
1025 ;;(define x86-jnl-rel8-opcode x86-jge-rel8-opcode)
1026 (define x86-jle-rel8-opcode #x7e)
1027 ;;(define x86-jng-rel8-opcode x86-jle-rel8-opcode)
1028 (define x86-jg-rel8-opcode #x7f)
1029 ;;(define x86-jnle-rel8-opcode x86-jg-rel8-opcode)
1031 (define (x86-jmp cgc opnd)
1032 (if (asm-label? opnd)
1033 (x86-jump-label cgc opnd x86-jmp-rel8-opcode)
1034 (x86-jump-general cgc opnd 4)))
1036 (define (x86-call cgc opnd)
1037 (if (asm-label? opnd)
1038 (x86-jump-label cgc opnd x86-call-rel32-opcode)
1039 (x86-jump-general cgc opnd 2)))
1041 (define (x86-jo cgc label) (x86-jump-label cgc label x86-jo-rel8-opcode))
1042 (define (x86-jno cgc label) (x86-jump-label cgc label x86-jno-rel8-opcode))
1043 (define (x86-jb cgc label) (x86-jump-label cgc label x86-jb-rel8-opcode))
1044 (define (x86-jae cgc label) (x86-jump-label cgc label x86-jae-rel8-opcode))
1045 (define (x86-je cgc label) (x86-jump-label cgc label x86-je-rel8-opcode))
1046 (define (x86-jne cgc label) (x86-jump-label cgc label x86-jne-rel8-opcode))
1047 (define (x86-jbe cgc label) (x86-jump-label cgc label x86-jbe-rel8-opcode))
1048 (define (x86-ja cgc label) (x86-jump-label cgc label x86-ja-rel8-opcode))
1049 (define (x86-js cgc label) (x86-jump-label cgc label x86-js-rel8-opcode))
1050 (define (x86-jns cgc label) (x86-jump-label cgc label x86-jns-rel8-opcode))
1051 (define (x86-jp cgc label) (x86-jump-label cgc label x86-jp-rel8-opcode))
1052 (define (x86-jnp cgc label) (x86-jump-label cgc label x86-jnp-rel8-opcode))
1053 (define (x86-jl cgc label) (x86-jump-label cgc label x86-jl-rel8-opcode))
1054 (define (x86-jge cgc label) (x86-jump-label cgc label x86-jge-rel8-opcode))
1055 (define (x86-jle cgc label) (x86-jump-label cgc label x86-jle-rel8-opcode))
1056 (define (x86-jg cgc label) (x86-jump-label cgc label x86-jg-rel8-opcode))
1058 (define (x86-jump-label cgc label opcode)
1060 (define (listing width)
1061 (if (codegen-context-listing-format cgc)
1063 (cond ((fx= opcode x86-jmp-rel8-opcode)
1065 ((fx= opcode x86-call-rel32-opcode)
1069 '#("jo" "jno" "jb" "jae" "je" "jne" "jbe" "ja"
1070 "js" "jns" "jp" "jnp" "jl" "jge" "jle" "jg")
1071 (fx- opcode x86-jo-rel8-opcode))))
1073 (asm-label-name label))))
1075 (define (label-dist label self offset)
1076 (fx- (asm-label-pos label)
1083 ;; short displacement (-128..127 bytes)
1085 (if (fx= opcode x86-call-rel32-opcode)
1089 (let ((dist (label-dist label self 2)))
1090 (if (asm-signed8? dist)
1094 (let ((dist (label-dist label self 2)))
1095 (asm-8 cb opcode) ;; opcode
1096 (asm-8 cb (fxand 255 dist))) ;; 8 bit distance
1099 ;; 32 bit relative address
1102 (cond ((or (fx= opcode x86-jmp-rel8-opcode)
1103 (fx= opcode x86-call-rel32-opcode))
1108 (let ((dist (label-dist label self 5)))
1109 (cond ((fx= opcode x86-jmp-rel8-opcode)
1110 (asm-8 cb x86-jmp-rel32-opcode) ;; opcode
1111 (asm-32-le cb dist)) ;; 32 bit distance
1112 ((fx= opcode x86-call-rel32-opcode)
1113 (asm-8 cb opcode) ;; opcode
1114 (asm-32-le cb dist)) ;; 32 bit distance
1116 ;; opcode is for a conditional jump
1117 (x86-esc-opcode cb) ;; escape opcode
1118 (asm-8 cb (fx+ #x10 opcode)) ;; opcode = #x80, #x81, etc
1119 (asm-32-le cb (fx- dist 1))))) ;; 32 bit distance
1122 (define (x86-jump-general cgc opnd field)
1124 (assert (or (not (x86-reg? opnd))
1125 (fx= (x86-reg-width opnd)
1126 (x86-word-width cgc)))
1127 "invalid width register" opnd)
1129 (x86-opnd-prefix cgc 0 0 opnd #f) ;; prefix (width is implicit)
1130 (asm-8 cgc #xff) ;; opcode
1131 (x86-opnd-modrm/sib cgc field opnd) ;; ModR/M
1133 (if (codegen-context-listing-format cgc)
1135 (if (fx= field 4) "jmp" "call")
1139 ;;;----------------------------------------------------------------------------
1141 ;;; X86 instructions: PUSH and POP.
1143 (define (x86-push cgc opnd)
1144 (x86-push-pop cgc opnd #x50))
1146 (define (x86-pop cgc opnd)
1147 (x86-push-pop cgc opnd #x58))
1149 (define (x86-push-pop cgc opnd op) ;; width is always width of stack pointer
1151 (define (listing opnd)
1152 (if (codegen-context-listing-format cgc)
1154 (if (fx= op #x50) "push" "pop")
1155 (x86-word-width cgc)
1156 (if (and #f ;; comment-out to avoid duplicate width qualifier in nasm format
1157 (x86-imm-int? opnd))
1158 (x86-imm-int (x86-imm-int-value opnd) 0)
1162 (if (and (x86-imm-int? opnd)
1163 (asm-signed8? (x86-imm-int-value opnd)))
1165 (asm-8 cgc #x6a) ;; opcode = #x6a
1166 (listing (x86-imm-encode cgc opnd 8)))
1168 (asm-8 cgc #x68) ;; opcode = #x68
1169 (listing (x86-imm-encode cgc opnd 32)))))
1172 (let ((field (x86-reg-field opnd)))
1174 (if (x86-reg32? opnd)
1176 (x86-assert-32bit-mode cgc)
1177 (assert (fx< field 8)
1178 "cannot push/pop extended registers in 32 bit mode"))
1180 (x86-assert-64bit-mode cgc)
1182 (asm-8 cgc #x41)))) ;; REX
1184 (asm-8 cgc (fx+ op ;; opcode = #x50-#x5f
1191 (x86-opnd-prefix cgc 0 0 opnd #f) ;; prefix (width is implicit)
1194 (if (fx= op #x50) ;; push?
1196 (asm-8 cgc #xff) ;; opcode = #xff
1199 (asm-8 cgc #x8f) ;; opcode = #x8f
1201 (x86-opnd-modrm/sib cgc field opnd)) ;; ModR/M
1205 (cond ((and (fx= op #x50) ;; push?
1206 (x86-imm-int? opnd))
1213 ;;;----------------------------------------------------------------------------
1215 ;;; X86 instructions: CWDE, CDQ, CBW, CWD, CDQE, and CQO.
1217 (define (x86-cwde cgc) (x86-widen cgc 0))
1218 (define (x86-cdq cgc) (x86-widen cgc 1))
1219 (define (x86-cbw cgc) (x86-widen cgc 2))
1220 (define (x86-cwd cgc) (x86-widen cgc 3))
1221 (define (x86-cdqe cgc) (x86-widen cgc 4))
1222 (define (x86-cqo cgc) (x86-widen cgc 5))
1224 (define (x86-widen cgc op)
1227 (if (codegen-context-listing-format cgc)
1230 '#("cwde" "cdq" "cbw" "cwd" "cdqe" "cqo")
1232 0))) ;; implicit width
1235 (x86-assert-64bit-mode cgc)
1236 (asm-8 cgc #x48)) ;; REX prefix
1238 (asm-8 cgc #x66))) ;; operand size override prefix
1240 (asm-8 cgc (fx+ #x98 (fxand op 1)))
1244 ;;;----------------------------------------------------------------------------
1246 ;;; X86 instructions: ROL, ROR, RCL, RCR, SHL, SHR, and SAR.
1248 (define (x86-rol cgc opnd1 opnd2 #!optional (width #f))
1249 (x86-shift cgc opnd1 opnd2 width 0))
1251 (define (x86-ror cgc opnd1 opnd2 #!optional (width #f))
1252 (x86-shift cgc opnd1 opnd2 width 1))
1254 (define (x86-rcl cgc opnd1 opnd2 #!optional (width #f))
1255 (x86-shift cgc opnd1 opnd2 width 2))
1257 (define (x86-rcr cgc opnd1 opnd2 #!optional (width #f))
1258 (x86-shift cgc opnd1 opnd2 width 3))
1260 (define (x86-shl cgc opnd1 opnd2 #!optional (width #f))
1261 (x86-shift cgc opnd1 opnd2 width 4))
1263 (define (x86-shr cgc opnd1 opnd2 #!optional (width #f))
1264 (x86-shift cgc opnd1 opnd2 width 5))
1266 (define (x86-sar cgc opnd1 opnd2 #!optional (width #f))
1267 (x86-shift cgc opnd1 opnd2 width 7))
1269 (define (x86-shift cgc opnd1 opnd2 width op)
1271 (define (listing width)
1272 (if (codegen-context-listing-format cgc)
1275 '#("rol" "ror" "rcl" "rcr" "shl" "shr" "???" "sar")
1280 (if (x86-imm-int? opnd2)
1281 (x86-imm-int (x86-imm-int-value opnd2) width)
1285 (define (general width)
1286 (x86-opnd-prefix-opnd cgc width opnd1) ;; prefix
1287 (cond ((x86-imm-int? opnd2)
1288 (let ((n (x86-imm-int-value opnd2)))
1289 (assert (and (>= n 0)
1291 "immediate shift count out of range" n)
1292 (asm-8 cgc (fx+ (if (fx= n 1) #xd0 #xc0) ;; opcode
1293 (if (fx= width 8) 0 1)))
1294 (x86-opnd-modrm/sib cgc op opnd1) ;; ModR/M
1297 ((eqv? opnd2 (x86-cl))
1298 (asm-8 cgc (fx+ #xd2 ;; opcode
1299 (if (fx= width 8) 0 1)))
1300 (x86-opnd-modrm/sib cgc op opnd1)) ;; ModR/M
1302 (error "invalid shift count operand" opnd2)))
1305 (assert (if (x86-reg? opnd1)
1307 (fx= (x86-reg-width opnd1) width))
1309 "missing or inconsistent operand width" width)
1311 (general (or width (x86-reg-width opnd1))))
1313 ;;;----------------------------------------------------------------------------
1315 ;;; X86 instructions: NOT and NEG.
1317 (define (x86-not cgc opnd #!optional (width #f))
1318 (x86-negate cgc opnd width 2))
1320 (define (x86-neg cgc opnd #!optional (width #f))
1321 (x86-negate cgc opnd width 3))
1323 (define (x86-negate cgc opnd width op)
1325 (define (listing width)
1326 (if (codegen-context-listing-format cgc)
1328 (if (fx= op 2) "not" "neg")
1332 (define (general width)
1333 (x86-opnd-prefix-opnd cgc width opnd) ;; prefix
1334 (asm-8 cgc (if (fx= width 8) #xf6 #xf7)) ;; opcode
1335 (x86-opnd-modrm/sib cgc op opnd) ;; ModR/M
1338 (assert (if (x86-reg? opnd)
1340 (fx= (x86-reg-width opnd) width))
1342 "missing or inconsistent operand width" width)
1344 (general (or width (x86-reg-width opnd))))
1346 ;;;----------------------------------------------------------------------------
1348 ;;; X86 instruction: TEST.
1350 (define (x86-test cgc opnd1 opnd2 #!optional (width #f))
1352 (define (listing width opnd1 opnd2)
1353 (if (codegen-context-listing-format cgc)
1360 (define (accumulator-imm width)
1361 (x86-opnd-prefix-opnd cgc width opnd1) ;; prefix
1362 (asm-8 cgc (if (fx= width 8) #xa8 #xa9)) ;; opcode
1365 (x86-imm-encode cgc opnd2 (fxmin 32 width))))
1367 (define (general-imm width)
1368 (x86-opnd-prefix-opnd cgc width opnd1) ;; prefix
1369 (asm-8 cgc (if (fx= width 8) #xf6 #xf7)) ;; opcode
1370 (x86-opnd-modrm/sib cgc 0 opnd1) ;; ModR/M
1373 (x86-imm-encode cgc opnd2 (fxmin 32 width))))
1375 (define (general-reg width)
1376 (x86-opnd-prefix-reg-opnd cgc opnd2 opnd1) ;; prefix
1377 (asm-8 cgc (if (fx= width 8) #x84 #x85)) ;; opcode
1378 (x86-opnd-modrm/sib-reg-opnd cgc opnd2 opnd1) ;; ModR/M
1383 (assert (cond ((x86-reg? opnd2)
1384 (and (or (not width)
1385 (fx= (x86-reg-width opnd2) width))
1386 (or (not (x86-reg? opnd1))
1387 (fx= (x86-reg-width opnd2) (x86-reg-width opnd1)))))
1390 (fx= (x86-reg-width opnd1) width)))
1393 "missing or inconsistent operand width" width)
1395 (if (x86-reg? opnd2)
1396 (general-reg (x86-reg-width opnd2))
1398 (assert (x86-imm-int? opnd2)
1399 "second operand must be a register or an immediate" opnd2)
1400 (if (x86-reg? opnd1)
1401 (let ((width (x86-reg-width opnd1))
1402 (field (x86-reg-field opnd1)))
1404 (accumulator-imm width)
1405 (general-imm width)))
1406 (general-imm width)))))
1408 ;;;----------------------------------------------------------------------------
1410 ;;; X86 instruction: XCHG.
1412 (define (x86-xchg cgc opnd1 opnd2)
1414 ;; opnd1 = source/destination1, opnd2 = source/destination2
1416 (define (listing width reg opnd swapped?)
1417 (if (codegen-context-listing-format cgc)
1421 (if swapped? opnd reg)
1422 (if swapped? reg opnd))))
1424 (define (accumulator-reg width acc reg swapped?)
1425 (let ((field (x86-reg-field reg)))
1426 (if (or #t ;; comment-out to avoid encoding "xchg eax,eax" as "nop" on x86-64
1427 (not (and (fx= width 32)
1429 (x86-64bit-mode? cgc))))
1431 (x86-opnd-prefix-reg-opnd cgc acc reg) ;; prefix
1432 (asm-8 cgc (fx+ #x90 (fxand 7 field))) ;; opcode
1433 (listing width acc reg swapped?))
1434 (general-reg width acc reg swapped?)))) ;; don't generate nop
1436 (define (general-reg width reg opnd swapped?)
1437 (x86-opnd-prefix-reg-opnd cgc reg opnd) ;; prefix
1438 (asm-8 cgc (if (fx= width 8) #x86 #x87)) ;; opcode
1439 (x86-opnd-modrm/sib-reg-opnd cgc reg opnd) ;; ModR/M
1440 (listing width reg opnd swapped?))
1442 (define (reg-op reg opnd swapped?)
1443 (let ((field (x86-reg-field reg))
1444 (width (x86-reg-width reg)))
1446 (let ((field2 (x86-reg-field opnd)))
1447 (assert (fx= width (x86-reg-width opnd)))
1448 (cond ((and (not (fx= width 8)) (fx= field 0)) ;; AX/EAX/RAX
1449 (accumulator-reg width reg opnd swapped?))
1450 ((and (not (fx= width 8)) (fx= field2 0)) ;; AX/EAX/RAX
1451 (accumulator-reg width opnd reg (not swapped?)))
1453 (if (or #t ;; comment-out for consistency with gnu assembler
1454 (not (eq? (codegen-context-listing-format cgc) 'gnu)))
1455 (general-reg width reg opnd swapped?)
1456 (general-reg width opnd reg (not swapped?))))))
1457 (general-reg width reg opnd swapped?))))
1459 (cond ((x86-reg? opnd1)
1460 (reg-op opnd1 opnd2 #f))
1462 (reg-op opnd2 opnd1 #t))
1464 (error "one of the two operands must be a register" opnd1 opnd2))))
1466 ;;;----------------------------------------------------------------------------
1468 ;;; X86 instructions: MUL, IMUL, DIV, and IDIV.
1470 (define (x86-mul cgc opnd #!optional (width #f))
1471 (x86-multiply-divide cgc opnd #f #f width 4))
1473 (define (x86-imul cgc opnd1 #!optional (opnd2 #f) (opnd3 #f) (width #f))
1474 (x86-multiply-divide cgc opnd1 opnd2 opnd3 width 5))
1476 (define (x86-div cgc opnd #!optional (width #f))
1477 (x86-multiply-divide cgc opnd #f #f width 6))
1479 (define (x86-idiv cgc opnd #!optional (width #f))
1480 (x86-multiply-divide cgc opnd #f #f width 7))
1482 (define (x86-multiply-divide cgc opnd1 opnd2 opnd3 width op)
1484 (define (listing width opnd1 opnd2 opnd3)
1485 (if (codegen-context-listing-format cgc)
1487 (vector-ref '#("mul" "imul" "div" "idiv") (fx- op 4))))
1507 (define (general-1-opnd width)
1508 (x86-opnd-prefix-opnd cgc width opnd1) ;; prefix
1509 (asm-8 cgc (if (fx= width 8) #xf6 #xf7)) ;; opcode
1510 (x86-opnd-modrm/sib cgc op opnd1) ;; ModR/M
1511 (listing width opnd1 #f #f))
1513 (define (register-2-opnds width)
1514 (assert (not (fx= width 8))
1515 "8 bit wide multiply not possible")
1516 (assert (or (not (x86-reg? opnd2))
1517 (fx= width (x86-reg-width opnd2)))
1518 "inconsistent width operands")
1519 (x86-opnd-prefix-reg-opnd cgc opnd1 opnd2) ;; prefix
1520 (x86-esc-opcode cgc) ;; escape opcode
1521 (asm-8 cgc #xaf) ;; opcode
1522 (x86-opnd-modrm/sib-reg-opnd cgc opnd1 opnd2) ;; ModR/M
1523 (listing width opnd1 opnd2 #f))
1525 (define (register-3-opnds width)
1527 (if (and (x86-imm-int? opnd3)
1528 (asm-signed8? (x86-imm-int-value opnd3)))
1531 (x86-opnd-prefix-reg-opnd cgc opnd1 opnd2) ;; prefix
1532 (asm-8 cgc (if (fx= imm-width 8) #x6b #x69)) ;; opcode
1533 (x86-opnd-modrm/sib-reg-opnd cgc opnd1 opnd2) ;; ModR/M
1537 (x86-imm-encode cgc opnd3 imm-width))))
1539 (assert (if (x86-reg? opnd1)
1541 (fx= (x86-reg-width opnd1) width))
1543 "missing or inconsistent operand width" width)
1545 (if (x86-reg? opnd1)
1546 (let ((width (x86-reg-width opnd1)))
1548 (register-3-opnds width))
1550 (register-2-opnds width))
1552 (general-1-opnd width))))
1553 (general-1-opnd width)))
1555 ;;;----------------------------------------------------------------------------
1557 ;;; X86 instructions: MOVZX, MOVSX, and MOVSXD.
1559 (define (x86-movzx cgc reg opnd #!optional (width #f))
1560 (x86-move-extended cgc reg opnd width #xb6))
1562 (define (x86-movsx cgc reg opnd #!optional (width #f))
1563 (x86-move-extended cgc reg opnd width #xbe))
1565 ;; Note: use x86-movsx instead of x86-movsxd
1566 ;;(define (x86-movsxd cgc reg opnd #!optional (width #f))
1567 ;; (x86-move-extended cgc reg opnd width #xbe))
1569 (define (x86-move-extended cgc reg opnd width op)
1571 ;; reg = destination, opnd = source
1573 (define (listing width-opnd)
1574 (if (codegen-context-listing-format cgc)
1576 (case (codegen-context-listing-format cgc)
1578 (if (fx= width-opnd 32)
1580 (list (if (fx= op #xb6)
1583 (x86-width-suffix cgc width-opnd))))
1585 (if (fx= width-opnd 32)
1594 (x86-force-width opnd width-opnd)))))
1596 (assert (x86-reg? reg)
1597 "destination of movzx/movsx/movsxd must be a register" reg)
1599 (assert (not (x86-reg8? reg))
1600 "destination of movzx/movsx/movsxd must not be an 8 bit register" reg)
1602 (assert (if (x86-reg? opnd)
1604 (fx= (x86-reg-width opnd) width))
1606 "missing or inconsistent operand width" width)
1608 (let ((width-reg (x86-reg-width reg))
1609 (width-opnd (or width (x86-reg-width opnd))))
1611 (assert (or (fx= width-opnd 8)
1613 (and (fx= op #xbe) ;; movsxd?
1614 (fx= width-opnd 32)))
1615 "invalid combination of operands" reg opnd)
1617 (x86-opnd-prefix-reg-opnd cgc reg opnd) ;; prefix
1618 (if (fx= width-opnd 32)
1619 (asm-8 cgc #x63) ;; opcode for movsxd
1621 (x86-esc-opcode cgc) ;; escape opcode
1622 (asm-8 cgc (fx+ op (if (fx= width-opnd 8) 0 1))))) ;; opcode
1623 (x86-opnd-modrm/sib-reg-opnd cgc reg opnd) ;; ModR/M
1625 (listing width-opnd)))
1627 ;;;----------------------------------------------------------------------------
1629 ;;; X86 instructions: BT, BTS, BTR, BTC, BSF, and BSR.
1631 (define (x86-bt cgc opnd1 opnd2 #!optional (width #f))
1632 (x86-bit-op cgc opnd1 opnd2 width 0)) ;; 0f a3 0f ba /4
1634 (define (x86-bts cgc opnd1 opnd2 #!optional (width #f))
1635 (x86-bit-op cgc opnd1 opnd2 width 1)) ;; 0f ab 0f ba /5
1637 (define (x86-btr cgc opnd1 opnd2 #!optional (width #f))
1638 (x86-bit-op cgc opnd1 opnd2 width 2)) ;; 0f b3 0f ba /6
1640 (define (x86-btc cgc opnd1 opnd2 #!optional (width #f))
1641 (x86-bit-op cgc opnd1 opnd2 width 3)) ;; 0f bb 0f ba /7
1643 (define (x86-bit-op cgc opnd1 opnd2 width op)
1645 (define (listing width)
1646 (if (codegen-context-listing-format cgc)
1649 '#("bt" "bts" "btr" "btc")
1653 (if (x86-imm-int? opnd2)
1654 (x86-imm-int (x86-imm-int-value opnd2) width)
1657 (define (general width)
1658 (cond ((x86-imm-int? opnd2)
1659 (let ((n (x86-imm-int-value opnd2)))
1660 (assert (and (>= n 0)
1662 "immediate bit position out of range" n)
1663 (x86-opnd-prefix-opnd cgc width opnd1) ;; prefix
1664 (x86-esc-opcode cgc) ;; escape opcode
1665 (asm-8 cgc #xba) ;; opcode
1666 (x86-opnd-modrm/sib cgc (fx+ op 4) opnd1) ;; ModR/M
1667 (asm-8 cgc n))) ;; immediate bit position
1669 (x86-opnd-prefix-reg-opnd cgc opnd2 opnd1) ;; prefix
1670 (x86-esc-opcode cgc) ;; escape opcode
1671 (asm-8 cgc (fx+ #xa3 (fxarithmetic-shift-left op 3))) ;; opcode
1672 (x86-opnd-modrm/sib-reg-opnd cgc opnd2 opnd1)) ;; ModR/M
1674 (error "invalid bit position operand" opnd2)))
1677 (assert (and (or (not (x86-reg? opnd1))
1679 (fx= (x86-reg-width opnd1) width))
1680 (or (not (x86-reg? opnd2))
1682 (fx= (x86-reg-width opnd2) width))
1683 (or (not (x86-reg? opnd1))
1684 (not (x86-reg? opnd2))
1685 (fx= (x86-reg-width opnd1) (x86-reg-width opnd2))))
1686 "missing or inconsistent operand width" width)
1688 (cond ((x86-reg? opnd1)
1689 (general (x86-reg-width opnd1)))
1691 (general (x86-reg-width opnd2)))
1695 ;;;============================================================================