! Copyright (C) 2005, 2010 Slava Pestov. ! See https://factorcode.org/license.txt for BSD license. USING: accessors alien arrays assocs byte-arrays classes.algebra classes.struct combinators compiler compiler.cfg compiler.cfg.comparisons compiler.cfg.instructions compiler.cfg.intrinsics compiler.cfg.registers compiler.cfg.stack-frame compiler.codegen.gc-maps compiler.codegen.labels compiler.codegen.relocation compiler.constants compiler.units cpu.architecture cpu.x86.assembler cpu.x86.assembler.operands cpu.x86.assembler.private cpu.x86.features cpu.x86.features.private fry io kernel layouts locals make math math.order memory namespaces sequences system vm vocabs ; QUALIFIED-WITH: alien.c-types c FROM: kernel.private => declare ; FROM: math => float ; IN: cpu.x86 ! Add some methods to the assembler to be more useful to the backend M: label JMP 0 JMP rc-relative label-fixup ; M: label JUMPcc [ 0 ] dip JUMPcc rc-relative label-fixup ; HOOK: stack-reg cpu ( -- reg ) HOOK: reserved-stack-space cpu ( -- n ) HOOK: pic-tail-reg cpu ( -- reg ) : stack@ ( n -- op ) stack-reg swap [+] ; : special-offset ( m -- n ) reserved-stack-space + ; : spill@ ( n -- op ) spill-offset special-offset stack@ ; : (%inc) ( n reg -- ) swap cells dup 0 > [ ADD ] [ neg SUB ] if ; inline : decr-stack-reg ( n -- ) [ dup cell = [ drop pic-tail-reg PUSH ] [ stack-reg swap SUB ] if ] unless-zero ; : incr-stack-reg ( n -- ) [ dup cell = [ drop pic-tail-reg POP ] [ stack-reg swap ADD ] if ] unless-zero ; : align-stack ( n -- n' ) 16 align ; M: x86 stack-frame-size (stack-frame-size) reserved-stack-space + cell + align-stack ; M: x86 complex-addressing? t ; M: x86 fused-unboxing? t ; M: x86 test-instruction? t ; M: x86 immediate-store? immediate-comparand? ; M: x86 %load-immediate { fixnum } declare [ 32-bit-version-of dup XOR ] [ MOV ] if-zero ; M: x86 %load-reference [ swap 0 MOV rc-absolute-cell rel-literal ] [ \ f type-number MOV ] if* ; HOOK: ds-reg cpu ( -- reg ) HOOK: rs-reg cpu ( -- reg ) : reg-stack ( n reg -- op ) swap cells neg [+] ; GENERIC: loc>operand ( loc -- operand ) M: ds-loc loc>operand n>> ds-reg reg-stack ; M: rs-loc loc>operand n>> rs-reg reg-stack ; M: x86 %peek loc>operand MOV ; M: x86 %replace loc>operand swap MOV ; M: x86 %replace-imm loc>operand swap { { [ dup not ] [ drop \ f type-number MOV ] } { [ dup fixnum? ] [ tag-fixnum MOV ] } [ [ 0 MOV ] dip rc-absolute rel-literal ] } cond ; M: x86 %clear 297 swap %replace-imm ; M: x86 %inc [ n>> ] [ ds-loc? ds-reg rs-reg ? ] bi (%inc) ; M: x86 %call 0 CALL rc-relative rel-word-pic ; : xt-tail-pic-offset ( -- n ) ! See the comment in vm/cpu-x86.hpp 4 1 + ; inline HOOK: %prepare-jump cpu ( -- ) M: x86 %jump %prepare-jump 0 JMP rc-relative rel-word-pic-tail ; M: x86 %jump-label 0 JMP rc-relative label-fixup ; M: x86 %return 0 RET ; : (%slot) ( obj slot scale tag -- op ) neg ; inline : (%slot-imm) ( obj slot tag -- op ) slot-offset [+] ; inline M: x86 %slot (%slot) MOV ; M: x86 %slot-imm (%slot-imm) MOV ; M: x86 %set-slot (%slot) swap MOV ; M: x86 %set-slot-imm (%slot-imm) swap MOV ; :: two-operand ( dst src1 src2 rep -- dst src ) dst src2 eq? dst src1 eq? not and [ "Cannot handle this case" throw ] when dst src1 rep %copy dst src2 ; inline :: one-operand ( dst src rep -- dst ) dst src rep %copy dst ; inline M: x86 %add 2over eq? [ nip ADD ] [ [+] LEA ] if ; M: x86 %add-imm 2over eq? [ nip { { 1 [ INC ] } { -1 [ DEC ] } [ ADD ] } case ] [ [+] LEA ] if ; M: x86 %sub int-rep two-operand SUB ; M: x86 %sub-imm 2over eq? [ nip { { 1 [ DEC ] } { -1 [ INC ] } [ SUB ] } case ] [ neg [+] LEA ] if ; M: x86 %mul int-rep two-operand IMUL2 ; M: x86 %mul-imm IMUL3 ; M: x86 %and int-rep two-operand AND ; M: x86 %and-imm int-rep two-operand AND ; M: x86 %or int-rep two-operand OR ; M: x86 %or-imm int-rep two-operand OR ; M: x86 %xor int-rep two-operand XOR ; M: x86 %xor-imm int-rep two-operand XOR ; M: x86 %shl-imm int-rep two-operand SHL ; M: x86 %shr-imm int-rep two-operand SHR ; M: x86 %sar-imm int-rep two-operand SAR ; M: x86 %min int-rep two-operand [ CMP ] [ CMOVG ] 2bi ; M: x86 %max int-rep two-operand [ CMP ] [ CMOVL ] 2bi ; M: x86 %not int-rep one-operand NOT ; M: x86 %neg int-rep one-operand NEG ; M: x86 %log2 BSR ; M: x86 %bit-count POPCNT ; ! A bit of logic to avoid using MOVSS/MOVSD for reg-reg moves ! since this induces partial register stalls GENERIC: copy-register* ( dst src rep -- ) GENERIC: copy-memory* ( dst src rep -- ) M: int-rep copy-register* drop MOV ; M: tagged-rep copy-register* drop MOV ; M: object copy-memory* copy-register* ; : ?spill-slot ( obj -- obj ) dup spill-slot? [ n>> spill@ ] when ; M: x86 %copy 2over eq? [ 3drop ] [ [ [ ?spill-slot ] bi@ ] dip 2over [ register? ] both? [ copy-register* ] [ copy-memory* ] if ] if ; : fixnum-overflow ( label dst src1 src2 cc quot -- ) swap [ [ int-rep two-operand ] dip call ] dip { { cc-o [ JO ] } { cc/o [ JNO ] } } case ; inline M: x86 %fixnum-add [ ADD ] fixnum-overflow ; M: x86 %fixnum-sub [ SUB ] fixnum-overflow ; M: x86 %fixnum-mul [ IMUL2 ] fixnum-overflow ; M: x86 %unbox-alien alien-offset [+] MOV ; M:: x86 %unbox-any-c-ptr ( dst src -- )