X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcompiler%2Fppc%2Farith.lisp;h=c633a1332170292d282e3f0c09c0f56856e64417;hb=d319b944d934f3efbb01a2a345c46bafd40857d0;hp=56910ac5b8a67ccaa1ee260dd4081b61522644d6;hpb=0db7f91050aeb2dc2f98946eefa251ffd6b96402;p=sbcl.git diff --git a/src/compiler/ppc/arith.lisp b/src/compiler/ppc/arith.lisp index 56910ac..c633a13 100644 --- a/src/compiler/ppc/arith.lisp +++ b/src/compiler/ppc/arith.lisp @@ -18,7 +18,6 @@ (:effects) (:affected)) - (define-vop (fixnum-unop fast-safe-arith-op) (:args (x :scs (any-reg))) (:results (res :scs (any-reg))) @@ -52,8 +51,6 @@ (:translate lognot) (:generator 1 (inst not res x))) - - ;;;; Binary fixnum operations. @@ -61,7 +58,7 @@ (define-vop (fast-fixnum-binop fast-safe-arith-op) (:args (x :target r :scs (any-reg zero)) - (y :target r :scs (any-reg zero))) + (y :target r :scs (any-reg zero))) (:arg-types tagged-num tagged-num) (:results (r :scs (any-reg))) (:result-types tagged-num) @@ -69,7 +66,7 @@ (define-vop (fast-unsigned-binop fast-safe-arith-op) (:args (x :target r :scs (unsigned-reg zero)) - (y :target r :scs (unsigned-reg zero))) + (y :target r :scs (unsigned-reg zero))) (:arg-types unsigned-num unsigned-num) (:results (r :scs (unsigned-reg))) (:result-types unsigned-num) @@ -77,18 +74,26 @@ (define-vop (fast-signed-binop fast-safe-arith-op) (:args (x :target r :scs (signed-reg zero)) - (y :target r :scs (signed-reg zero))) + (y :target r :scs (signed-reg zero))) (:arg-types signed-num signed-num) (:results (r :scs (signed-reg))) (:result-types signed-num) (:note "inline (signed-byte 32) arithmetic")) - (define-vop (fast-fixnum-binop-c fast-safe-arith-op) (:args (x :target r :scs (any-reg zero))) (:info y) (:arg-types tagged-num - (:constant (and (signed-byte 14) (not (integer 0 0))))) + (:constant (and (signed-byte 14) (not (integer 0 0))))) + (:results (r :scs (any-reg))) + (:result-types tagged-num) + (:note "inline fixnum arithmetic")) + +(define-vop (fast-fixnum-binop30-c fast-safe-arith-op) + (:args (x :target r :scs (any-reg zero))) + (:info y) + (:arg-types tagged-num + (:constant (and (signed-byte 30) (not (integer 0 0))))) (:results (r :scs (any-reg))) (:result-types tagged-num) (:note "inline fixnum arithmetic")) @@ -97,7 +102,16 @@ (:args (x :target r :scs (any-reg zero))) (:info y) (:arg-types tagged-num - (:constant (and (unsigned-byte 14) (not (integer 0 0))))) + (:constant (and (unsigned-byte 14) (not (integer 0 0))))) + (:results (r :scs (any-reg))) + (:result-types tagged-num) + (:note "inline fixnum logical op")) + +(define-vop (fast-fixnum-logop30-c fast-safe-arith-op) + (:args (x :target r :scs (any-reg zero))) + (:info y) + (:arg-types tagged-num + (:constant (and (unsigned-byte 16) (not (integer 0 0))))) (:results (r :scs (any-reg))) (:result-types tagged-num) (:note "inline fixnum logical op")) @@ -106,25 +120,61 @@ (:args (x :target r :scs (unsigned-reg zero))) (:info y) (:arg-types unsigned-num - (:constant (and (signed-byte 16) (not (integer 0 0))))) + (:constant (and (signed-byte 16) (not (integer 0 0))))) (:results (r :scs (unsigned-reg))) (:result-types unsigned-num) (:note "inline (unsigned-byte 32) arithmetic")) +(define-vop (fast-unsigned-binop32-c fast-safe-arith-op) + (:args (x :target r :scs (unsigned-reg zero))) + (:info y) + (:arg-types unsigned-num + (:constant (and (unsigned-byte 32) (not (integer 0 0))))) + (:results (r :scs (unsigned-reg))) + (:result-types unsigned-num) + (:note "inline (unsigned-byte 32) arithmetic")) + +(define-vop (fast-signed-binop32-c fast-safe-arith-op) + (:args (x :target r :scs (signed-reg zero))) + (:info y) + (:arg-types signed-num + (:constant (and (signed-byte 32) (not (integer 0 0))))) + (:results (r :scs (signed-reg))) + (:result-types signed-num) + (:note "inline (signed-byte 32) arithmetic")) + (define-vop (fast-unsigned-logop-c fast-safe-arith-op) (:args (x :target r :scs (unsigned-reg zero))) (:info y) (:arg-types unsigned-num - (:constant (and (unsigned-byte 16) (not (integer 0 0))))) + (:constant (and (unsigned-byte 16) (not (integer 0 0))))) (:results (r :scs (unsigned-reg))) (:result-types unsigned-num) (:note "inline (unsigned-byte 32) logical op")) +(define-vop (fast-unsigned-logop32-c fast-safe-arith-op) + (:args (x :target r :scs (unsigned-reg zero))) + (:info y) + (:arg-types unsigned-num + (:constant (and (unsigned-byte 32) (not (integer 0 0))))) + (:results (r :scs (unsigned-reg))) + (:result-types unsigned-num) + (:note "inline (unsigned-byte 32) logical op")) + +(define-vop (fast-signed-logop32-c fast-safe-arith-op) + (:args (x :target r :scs (signed-reg zero))) + (:info y) + (:arg-types signed-num + (:constant (and (unsigned-byte 32) (not (integer 0 0))))) + (:results (r :scs (signed-reg))) + (:result-types signed-num) + (:note "inline (signed-byte 32) logical op")) + (define-vop (fast-signed-binop-c fast-safe-arith-op) (:args (x :target r :scs (signed-reg zero))) (:info y) (:arg-types signed-num - (:constant (and (signed-byte 16) (not (integer 0 0))))) + (:constant (and (signed-byte 16) (not (integer 0 0))))) (:results (r :scs (signed-reg))) (:result-types signed-num) (:note "inline (signed-byte 32) arithmetic")) @@ -133,87 +183,245 @@ (:args (x :target r :scs (signed-reg zero))) (:info y) (:arg-types signed-num - (:constant (and (unsigned-byte 16) (not (integer 0 0))))) + (:constant (and (unsigned-byte 16) (not (integer 0 0))))) (:results (r :scs (signed-reg))) (:result-types signed-num) - (:note "inline (signed-byte 32) arithmetic")) - + (:note "inline (signed-byte 32) logical op")) (eval-when (:compile-toplevel :load-toplevel :execute) -(defmacro define-var-binop (translate untagged-penalty op) +(defmacro !define-var-binop (translate untagged-penalty op + &optional arg-swap restore-fixnum-mask) `(progn (define-vop (,(symbolicate "FAST-" translate "/FIXNUM=>FIXNUM") - fast-fixnum-binop) + fast-fixnum-binop) + ,@(when restore-fixnum-mask + `((:temporary (:sc non-descriptor-reg) temp))) (:translate ,translate) (:generator 2 - (inst ,op r x y))) + ,(if arg-swap + `(inst ,op ,(if restore-fixnum-mask 'temp 'r) y x) + `(inst ,op ,(if restore-fixnum-mask 'temp 'r) x y)) + ;; FIXME: remind me what convention we used for 64bitizing + ;; stuff? -- CSR, 2003-08-27 + ,@(when restore-fixnum-mask + `((inst clrrwi r temp (1- n-lowtag-bits)))))) (define-vop (,(symbolicate "FAST-" translate "/SIGNED=>SIGNED") - fast-signed-binop) + fast-signed-binop) (:translate ,translate) (:generator ,(1+ untagged-penalty) - (inst ,op r x y))) + ,(if arg-swap + `(inst ,op r y x) + `(inst ,op r x y)))) (define-vop (,(symbolicate "FAST-" translate "/UNSIGNED=>UNSIGNED") - fast-unsigned-binop) + fast-unsigned-binop) (:translate ,translate) (:generator ,(1+ untagged-penalty) - (inst ,op r x y))))) - - -(defmacro define-const-binop (translate untagged-penalty op) + ,(if arg-swap + `(inst ,op r y x) + `(inst ,op r x y)))))) + +;;; FIXME: the code has really only been checked for adds; we could do +;;; subtracts, too, but my brain is not up to the task of figuring out +;;; signs and borrows. +(defmacro !define-const-binop (translate untagged-penalty op &optional (shifted-op nil)) `(progn - (define-vop (,(symbolicate 'fast- translate '-c/fixnum=>fixnum) - fast-fixnum-binop-c) + ,(if shifted-op + 'fast-fixnum-binop30-c + 'fast-fixnum-binop-c)) (:translate ,translate) + ,@(when shifted-op + `((:temporary (:sc any-reg :target r) temp))) (:generator 1 - (inst ,op r x (fixnumize y)))) + ,(if shifted-op + `(let* ((y (fixnumize y)) + (high-half (ldb (byte 16 16) y)) + (low-half (ldb (byte 16 0) y))) + ;; Compare %LR in insts.lisp. + (cond + ((and (logbitp 15 low-half) (= high-half #xffff)) + ;; Let sign-extension do the work for us, but make sure + ;; to turn LOW-HALF into a signed integer. + (inst ,op r x (dpb low-half (byte 16 0) -1))) + ((and (not (logbitp 15 low-half)) (zerop high-half)) + (inst ,op r x low-half)) + ((zerop low-half) + (inst ,shifted-op r x (if (logbitp 15 high-half) + (dpb high-half (byte 16 0) -1) + high-half))) + (t + ;; Check to see whether compensating for the sign bit + ;; of LOW-HALF is necessary. + (let ((high-half (let ((top (if (logbitp 15 low-half) + (ldb (byte 16 0) + (1+ high-half)) + high-half))) + (if (logbitp 15 top) + (dpb top (byte 16 0) -1) + top)))) + (inst ,shifted-op temp x high-half) + (inst ,op r temp low-half))))) + `(inst ,op r x (fixnumize y))))) (define-vop (,(symbolicate 'fast- translate '-c/signed=>signed) - fast-signed-binop-c) + ,(if shifted-op + 'fast-signed-binop32-c + 'fast-signed-binop-c)) (:translate ,translate) + ,@(when shifted-op + `((:temporary (:sc non-descriptor-reg :target r) temp))) (:generator ,untagged-penalty - (inst ,op r x y))) + ,(if shifted-op + `(let ((high-half (ldb (byte 16 16) y)) + (low-half (ldb (byte 16 0) y))) + ;; Compare %LR in insts.lisp. + (cond + ((and (logbitp 15 low-half) (= high-half #xffff)) + ;; Let sign-extension do the work for us, but make sure + ;; to turn LOW-HALF into a signed integer. + (inst ,op r x (dpb low-half (byte 16 0) -1))) + ((and (not (logbitp 15 low-half)) (zerop high-half)) + (inst ,op r x low-half)) + ((zerop low-half) + (inst ,shifted-op r x (if (logbitp 15 high-half) + (dpb high-half (byte 16 0) -1) + high-half))) + (t + ;; Check to see whether compensating for the sign bit + ;; of LOW-HALF is necessary. + (let ((high-half (let ((top (if (logbitp 15 low-half) + (ldb (byte 16 0) + (1+ high-half)) + high-half))) + (if (logbitp 15 top) + (dpb top (byte 16 0) -1) + top)))) + (inst ,shifted-op temp x high-half) + (inst ,op r temp low-half))))) + `(inst ,op r x y)))) (define-vop (,(symbolicate 'fast- translate '-c/unsigned=>unsigned) - fast-unsigned-binop-c) + ,(if shifted-op + 'fast-unsigned-binop32-c + 'fast-unsigned-binop-c)) (:translate ,translate) + ,@(when shifted-op + `((:temporary (:sc non-descriptor-reg :target r) temp))) (:generator ,untagged-penalty - (inst ,op r x y))))) - -(defmacro define-const-logop (translate untagged-penalty op) + ,(if shifted-op + `(let ((high-half (ldb (byte 16 16) y)) + (low-half (ldb (byte 16 0) y))) + ;; Compare %LR in insts.lisp. + (cond + ((and (logbitp 15 low-half) (= high-half #xffff)) + ;; Let sign-extension do the work for us, but make sure + ;; to turn LOW-HALF into a signed integer. + (inst ,op r x (dpb low-half (byte 16 0) -1))) + ((and (not (logbitp 15 low-half)) (zerop high-half)) + (inst ,op r x low-half)) + ((zerop low-half) + (inst ,shifted-op r x (if (logbitp 15 high-half) + (dpb high-half (byte 16 0) -1) + high-half))) + (t + ;; Check to see whether compensating for the sign bit + ;; of LOW-HALF is necessary. + (let ((high-half (let ((top (if (logbitp 15 low-half) + (ldb (byte 16 0) + (1+ high-half)) + high-half))) + (if (logbitp 15 top) + (dpb top (byte 16 0) -1) + top)))) + (inst ,shifted-op temp x high-half) + (inst ,op r temp low-half))))) + `(inst ,op r x y)))))) + +;;; For logical operations, we don't have to worry about signed bit +;;; propagation from the lower half of a 32-bit operand. +(defmacro !define-const-logop (translate untagged-penalty op &optional (shifted-op nil)) `(progn - (define-vop (,(symbolicate 'fast- translate '-c/fixnum=>fixnum) - fast-fixnum-logop-c) + ,(if shifted-op + 'fast-fixnum-logop30-c + 'fast-fixnum-logop-c)) (:translate ,translate) + ,@(when shifted-op + `((:temporary (:sc any-reg :target r) temp))) (:generator 1 - (inst ,op r x (fixnumize y)))) + ,(if shifted-op + `(let* ((y (fixnumize y)) + (high-half (ldb (byte 16 16) y)) + (low-half (ldb (byte 16 0) y))) + (cond + ((zerop high-half) (inst ,op r x low-half)) + ((zerop low-half) (inst ,shifted-op r x high-half)) + (t + (inst ,shifted-op temp x high-half) + (inst ,op r temp low-half)))) + `(inst ,op r x (fixnumize y))))) (define-vop (,(symbolicate 'fast- translate '-c/signed=>signed) - fast-signed-logop-c) + ,(if shifted-op + 'fast-signed-logop32-c + 'fast-signed-logop-c)) (:translate ,translate) + ,@(when shifted-op + `((:temporary (:sc non-descriptor-reg :target r) temp))) (:generator ,untagged-penalty - (inst ,op r x y))) + ,(if shifted-op + `(let ((high-half (ldb (byte 16 16) y)) + (low-half (ldb (byte 16 0) y))) + (cond + ((zerop high-half) (inst ,op r x low-half)) + ((zerop low-half) (inst ,shifted-op r x high-half)) + (t + (inst ,shifted-op temp x high-half) + (inst ,op r temp low-half)))) + `(inst ,op r x y)))) (define-vop (,(symbolicate 'fast- translate '-c/unsigned=>unsigned) - fast-unsigned-logop-c) + ,(if shifted-op + 'fast-unsigned-logop32-c + 'fast-unsigned-logop-c)) (:translate ,translate) + ,@(when shifted-op + `((:temporary (:sc non-descriptor-reg :target r) temp))) (:generator ,untagged-penalty - (inst ,op r x y))))) + ,(if shifted-op + `(let ((high-half (ldb (byte 16 16) y)) + (low-half (ldb (byte 16 0) y))) + (cond + ((zerop high-half) (inst ,op r x low-half)) + ((zerop low-half) (inst ,shifted-op r x high-half)) + (t + (inst ,shifted-op temp x high-half) + (inst ,op r temp low-half)))) + `(inst ,op r x y)))))) ); eval-when -(define-var-binop + 4 add) -(define-var-binop - 4 sub) -(define-var-binop logand 2 and) -(define-var-binop logandc2 2 andc) -(define-var-binop logior 2 or) -(define-var-binop logorc2 2 orc) -(define-var-binop logxor 2 xor) -(define-var-binop logeqv 2 eqv) - -(define-const-binop + 4 addi) -(define-const-binop - 4 subi) -(define-const-logop logand 2 andi.) -(define-const-logop logior 2 ori) -(define-const-logop logxor 2 xori) +(!define-var-binop + 4 add) +(!define-var-binop - 4 sub) +(!define-var-binop logand 2 and) +(!define-var-binop logandc1 2 andc t) +(!define-var-binop logandc2 2 andc) +(!define-var-binop logior 2 or) +(!define-var-binop logorc1 2 orc t t) +(!define-var-binop logorc2 2 orc nil t) +(!define-var-binop logxor 2 xor) +(!define-var-binop logeqv 2 eqv nil t) +(!define-var-binop lognand 2 nand nil t) +(!define-var-binop lognor 2 nor nil t) + +(!define-const-binop + 4 addi addis) +(!define-const-binop - 4 subi) +;;; Implementing a 32-bit immediate version of LOGAND wouldn't be any +;;; better than loading the 32-bit constant via LR and then performing +;;; an /AND/. So don't bother. (It would be better in some cases, such +;;; as when one half of the word is zeros--we save a register--but we +;;; would have specified one temporary register in the VOP, so we lose +;;; any possible advantage.) +(!define-const-logop logand 2 andi.) +(!define-const-logop logior 2 ori oris) +(!define-const-logop logxor 2 xori xoris) ;;; Special case fixnum + and - that trap on overflow. Useful when we @@ -226,14 +434,13 @@ (:note "safe inline fixnum arithmetic") (:generator 4 (let* ((no-overflow (gen-label))) - (inst mcrxr :cr0) + (inst mtxer zero-tn) (inst addo. r x y) (inst bns no-overflow) (inst unimp (logior (ash (reg-tn-encoding r) 5) - fixnum-additive-overflow-trap)) + fixnum-additive-overflow-trap)) (emit-label no-overflow)))) - (define-vop (-/fixnum fast--/fixnum=>fixnum) (:policy :safe) (:results (r :scs (any-reg descriptor-reg))) @@ -241,58 +448,131 @@ (:note "safe inline fixnum arithmetic") (:generator 4 (let* ((no-overflow (gen-label))) - (inst mcrxr :cr0) + (inst mtxer zero-tn) (inst subo. r x y) (inst bns no-overflow) (inst unimp (logior (ash (reg-tn-encoding r) 5) - fixnum-additive-overflow-trap)) + fixnum-additive-overflow-trap)) (emit-label no-overflow)))) +(define-vop (fast-*/fixnum=>fixnum fast-fixnum-binop) + (:temporary (:scs (non-descriptor-reg)) temp) + (:translate *) + (:generator 2 + (inst srawi temp y 2) + (inst mullw r x temp))) + +(define-vop (fast-*-c/fixnum=>fixnum fast-fixnum-binop-c) + (:translate *) + (:arg-types tagged-num + (:constant (and (signed-byte 16) (not (integer 0 0))))) + (:generator 1 + (inst mulli r x y))) + +(define-vop (fast-*-bigc/fixnum=>fixnum fast-fixnum-binop-c) + (:translate *) + (:arg-types tagged-num + (:constant (and fixnum (not (signed-byte 16))))) + (:temporary (:scs (non-descriptor-reg)) temp) + (:generator 1 + (inst lr temp y) + (inst mullw r x temp))) + +(define-vop (fast-*/signed=>signed fast-signed-binop) + (:translate *) + (:generator 4 + (inst mullw r x y))) +(define-vop (fast-*-c/signed=>signed fast-signed-binop-c) + (:translate *) + (:generator 3 + (inst mulli r x y))) + +(define-vop (fast-*/unsigned=>unsigned fast-unsigned-binop) + (:translate *) + (:generator 4 + (inst mullw r x y))) + +(define-vop (fast-*-c/unsigned=>unsigned fast-unsigned-binop-c) + (:translate *) + (:generator 3 + (inst mulli r x y))) + ;;; Shifting +(macrolet ((def (name sc-type type result-type cost) + `(define-vop (,name) + (:note "inline ASH") + (:translate ash) + (:args (number :scs (,sc-type)) + (amount :scs (signed-reg unsigned-reg immediate))) + (:arg-types ,type positive-fixnum) + (:results (result :scs (,result-type))) + (:result-types ,type) + (:policy :fast-safe) + (:generator ,cost + (sc-case amount + ((signed-reg unsigned-reg) + (inst slw result number amount)) + (immediate + (let ((amount (tn-value amount))) + (aver (> amount 0)) + (inst slwi result number amount)))))))) + ;; FIXME: There's the opportunity for a sneaky optimization here, I + ;; think: a FAST-ASH-LEFT-C/FIXNUM=>SIGNED vop. -- CSR, 2003-09-03 + (def fast-ash-left/fixnum=>fixnum any-reg tagged-num any-reg 2) + (def fast-ash-left/signed=>signed signed-reg signed-num signed-reg 3) + (def fast-ash-left/unsigned=>unsigned unsigned-reg unsigned-num unsigned-reg 3)) + (define-vop (fast-ash/unsigned=>unsigned) (:note "inline ASH") (:args (number :scs (unsigned-reg) :to :save) - (amount :scs (signed-reg immediate))) + (amount :scs (signed-reg))) (:arg-types (:or unsigned-num) signed-num) (:results (result :scs (unsigned-reg))) (:result-types unsigned-num) (:translate ash) (:policy :fast-safe) (:temporary (:sc non-descriptor-reg) ndesc) - (:generator 3 - (sc-case amount - (signed-reg - (let ((positive (gen-label)) - (done (gen-label))) - (inst cmpwi amount 0) - (inst neg ndesc amount) - (inst bge positive) - (inst cmpwi ndesc 31) - (inst srw result number ndesc) - (inst ble done) - (inst srwi result number 31) - (inst b done) - - (emit-label positive) - ;; The result-type assures us that this shift will not overflow. - (inst slw result number amount) - - (emit-label done))) + (:generator 5 + (let ((positive (gen-label)) + (done (gen-label))) + (inst cmpwi amount 0) + (inst neg ndesc amount) + (inst bge positive) + (inst cmpwi ndesc 31) + (inst srw result number ndesc) + (inst ble done) + (move result zero-tn) + (inst b done) + + (emit-label positive) + ;; The result-type assures us that this shift will not overflow. + (inst slw result number amount) - (immediate - (let ((amount (tn-value amount))) - (if (minusp amount) - (let ((amount (min 31 (- amount)))) - (inst srwi result number amount)) - (inst slwi result number amount))))))) + (emit-label done)))) +(define-vop (fast-ash-c/unsigned=>unsigned) + (:note "inline constant ASH") + (:args (number :scs (unsigned-reg))) + (:info amount) + (:arg-types unsigned-num (:constant integer)) + (:results (result :scs (unsigned-reg))) + (:result-types unsigned-num) + (:translate ash) + (:policy :fast-safe) + (:generator 4 + (cond + ((and (minusp amount) (< amount -31)) (move result zero-tn)) + ((minusp amount) (inst srwi result number (- amount))) + ;; possible because this is used in the modular version too + ((> amount 31) (move result zero-tn)) + (t (inst slwi result number amount))))) (define-vop (fast-ash/signed=>signed) (:note "inline ASH") (:args (number :scs (signed-reg) :to :save) - (amount :scs (signed-reg immediate))) + (amount :scs (signed-reg immediate))) (:arg-types (:or signed-num) signed-num) (:results (result :scs (signed-reg))) (:result-types (:or signed-num)) @@ -303,28 +583,28 @@ (sc-case amount (signed-reg (let ((positive (gen-label)) - (done (gen-label))) - (inst cmpwi amount 0) - (inst neg ndesc amount) - (inst bge positive) - (inst cmpwi ndesc 31) - (inst sraw result number ndesc) - (inst ble done) - (inst srawi result number 31) - (inst b done) - - (emit-label positive) - ;; The result-type assures us that this shift will not overflow. - (inst slw result number amount) - - (emit-label done))) + (done (gen-label))) + (inst cmpwi amount 0) + (inst neg ndesc amount) + (inst bge positive) + (inst cmpwi ndesc 31) + (inst sraw result number ndesc) + (inst ble done) + (inst srawi result number 31) + (inst b done) + + (emit-label positive) + ;; The result-type assures us that this shift will not overflow. + (inst slw result number amount) + + (emit-label done))) (immediate (let ((amount (tn-value amount))) - (if (minusp amount) - (let ((amount (min 31 (- amount)))) - (inst srawi result number amount)) - (inst slwi result number amount))))))) + (if (minusp amount) + (let ((amount (min 31 (- amount)))) + (inst srawi result number amount)) + (inst slwi result number amount))))))) @@ -334,19 +614,29 @@ (:policy :fast-safe) (:args (arg :scs (signed-reg))) (:arg-types signed-num) - (:results (res :scs (any-reg))) - (:result-types positive-fixnum) - (:temporary (:scs (non-descriptor-reg) :to (:argument 0)) shift) + (:results (res :scs (unsigned-reg))) + (:result-types unsigned-num) (:generator 6 ; (integer-length arg) = (- 32 (cntlz (if (>= arg 0) arg (lognot arg)))) (let ((nonneg (gen-label))) - (inst cntlzw. shift arg) + (inst cntlzw. res arg) (inst bne nonneg) - (inst not shift arg) - (inst cntlzw shift shift) + (inst not res arg) + (inst cntlzw res res) (emit-label nonneg) - (inst slwi shift shift 2) - (inst subfic res shift (fixnumize 32))))) + (inst subfic res res 32)))) + +(define-vop (unsigned-byte-32-len) + (:translate integer-length) + (:note "inline (unsigned-byte 32) integer-length") + (:policy :fast-safe) + (:args (arg :scs (unsigned-reg))) + (:arg-types unsigned-num) + (:results (res :scs (unsigned-reg))) + (:result-types unsigned-num) + (:generator 4 + (inst cntlzw res arg) + (inst subfic res res 32))) (define-vop (unsigned-byte-32-count) (:translate logcount) @@ -359,7 +649,7 @@ (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) shift temp) (:generator 30 (let ((loop (gen-label)) - (done (gen-label))) + (done (gen-label))) (inst add. shift zero-tn arg) (move res zero-tn) (inst beq done) @@ -373,6 +663,56 @@ (emit-label done)))) +;;;; Modular functions: +(define-modular-fun lognot-mod32 (x) lognot :unsigned 32) +(define-vop (lognot-mod32/unsigned=>unsigned) + (:translate lognot-mod32) + (:args (x :scs (unsigned-reg))) + (:arg-types unsigned-num) + (:results (res :scs (unsigned-reg))) + (:result-types unsigned-num) + (:policy :fast-safe) + (:generator 1 + (inst not res x))) + +(define-vop (fast-ash-left-mod32-c/unsigned=>unsigned + fast-ash-c/unsigned=>unsigned) + (:translate ash-left-mod32)) + +(define-vop (fast-ash-left-mod32/unsigned=>unsigned + fast-ash-left/unsigned=>unsigned)) +(deftransform ash-left-mod32 ((integer count) + ((unsigned-byte 32) (unsigned-byte 5))) + (when (sb!c::constant-lvar-p count) + (sb!c::give-up-ir1-transform)) + '(%primitive fast-ash-left-mod32/unsigned=>unsigned integer count)) + +(macrolet + ((define-modular-backend (fun &optional constantp) + (let ((mfun-name (symbolicate fun '-mod32)) + (modvop (symbolicate 'fast- fun '-mod32/unsigned=>unsigned)) + (modcvop (symbolicate 'fast- fun 'mod32-c/unsigned=>unsigned)) + (vop (symbolicate 'fast- fun '/unsigned=>unsigned)) + (cvop (symbolicate 'fast- fun '-c/unsigned=>unsigned))) + `(progn + (define-modular-fun ,mfun-name (x y) ,fun :unsigned 32) + (define-vop (,modvop ,vop) + (:translate ,mfun-name)) + ,@(when constantp + `((define-vop (,modcvop ,cvop) + (:translate ,mfun-name)))))))) + (define-modular-backend + t) + (define-modular-backend - t) + (define-modular-backend * t) + (define-modular-backend logxor t) + (define-modular-backend logeqv) + (define-modular-backend lognand) + (define-modular-backend lognor) + (define-modular-backend logandc1) + (define-modular-backend logandc2) + (define-modular-backend logorc1) + (define-modular-backend logorc2)) + ;;;; Binary conditional VOPs: (define-vop (fast-conditional) @@ -384,7 +724,7 @@ (define-vop (fast-conditional/fixnum fast-conditional) (:args (x :scs (any-reg zero)) - (y :scs (any-reg zero))) + (y :scs (any-reg zero))) (:arg-types tagged-num tagged-num) (:note "inline fixnum comparison")) @@ -395,7 +735,7 @@ (define-vop (fast-conditional/signed fast-conditional) (:args (x :scs (signed-reg zero)) - (y :scs (signed-reg zero))) + (y :scs (signed-reg zero))) (:arg-types signed-num signed-num) (:note "inline (signed-byte 32) comparison")) @@ -406,7 +746,7 @@ (define-vop (fast-conditional/unsigned fast-conditional) (:args (x :scs (unsigned-reg zero)) - (y :scs (unsigned-reg zero))) + (y :scs (unsigned-reg zero))) (:arg-types unsigned-num unsigned-num) (:note "inline (unsigned-byte 32) comparison")) @@ -415,7 +755,6 @@ (:arg-types unsigned-num (:constant (unsigned-byte 16))) (:info target not-p y)) - (define-vop (fast-if-unsigned) + (:translate sb!bignum:%lognot)) (define-vop (fixnum-to-digit) - (:translate sb!bignum::%fixnum-to-digit) + (:translate sb!bignum:%fixnum-to-digit) (:policy :fast-safe) (:args (fixnum :scs (any-reg))) (:arg-types tagged-num) @@ -807,52 +1077,52 @@ (define-vop (bignum-floor) - (:translate sb!bignum::%floor) + (:translate sb!bignum:%floor) (:policy :fast-safe) (:args (num-high :scs (unsigned-reg) :target rem) - (num-low :scs (unsigned-reg) :target rem-low) - (denom :scs (unsigned-reg) :to (:eval 1))) + (num-low :scs (unsigned-reg) :target rem-low) + (denom :scs (unsigned-reg) :to (:eval 1))) (:arg-types unsigned-num unsigned-num unsigned-num) (:temporary (:scs (unsigned-reg) :from (:argument 1)) rem-low) (:temporary (:scs (unsigned-reg) :from (:eval 0)) temp) (:results (quo :scs (unsigned-reg) :from (:eval 0)) - (rem :scs (unsigned-reg) :from (:argument 0))) + (rem :scs (unsigned-reg) :from (:argument 0))) (:result-types unsigned-num unsigned-num) (:generator 325 ; number of inst assuming targeting works. (move rem num-high) (move rem-low num-low) (flet ((maybe-subtract (&optional (guess temp)) - (inst subi temp guess 1) - (inst and temp temp denom) - (inst sub rem rem temp)) - (sltu (res x y) - (inst subfc res y x) - (inst subfe res res res) - (inst neg res res))) + (inst subi temp guess 1) + (inst and temp temp denom) + (inst sub rem rem temp)) + (sltu (res x y) + (inst subfc res y x) + (inst subfe res res res) + (inst neg res res))) (sltu quo rem denom) (maybe-subtract quo) (dotimes (i 32) - (inst slwi rem rem 1) - (inst srwi temp rem-low 31) - (inst or rem rem temp) - (inst slwi rem-low rem-low 1) - (sltu temp rem denom) - (inst slwi quo quo 1) - (inst or quo quo temp) - (maybe-subtract))) + (inst slwi rem rem 1) + (inst srwi temp rem-low 31) + (inst or rem rem temp) + (inst slwi rem-low rem-low 1) + (sltu temp rem denom) + (inst slwi quo quo 1) + (inst or quo quo temp) + (maybe-subtract))) (inst not quo quo))) #| (define-vop (bignum-floor) - (:translate sb!bignum::%floor) + (:translate sb!bignum:%floor) (:policy :fast-safe) (:args (div-high :scs (unsigned-reg) :target rem) - (div-low :scs (unsigned-reg) :target quo) - (divisor :scs (unsigned-reg))) + (div-low :scs (unsigned-reg) :target quo) + (divisor :scs (unsigned-reg))) (:arg-types unsigned-num unsigned-num unsigned-num) (:results (quo :scs (unsigned-reg) :from (:argument 1)) - (rem :scs (unsigned-reg) :from (:argument 0))) + (rem :scs (unsigned-reg) :from (:argument 0))) (:result-types unsigned-num unsigned-num) (:generator 300 (inst mtmq div-low) @@ -861,7 +1131,7 @@ |# (define-vop (signify-digit) - (:translate sb!bignum::%fixnum-digit-with-correct-sign) + (:translate sb!bignum:%fixnum-digit-with-correct-sign) (:policy :fast-safe) (:args (digit :scs (unsigned-reg) :target res)) (:arg-types unsigned-num) @@ -876,10 +1146,10 @@ (define-vop (digit-ashr) - (:translate sb!bignum::%ashr) + (:translate sb!bignum:%ashr) (:policy :fast-safe) (:args (digit :scs (unsigned-reg)) - (count :scs (unsigned-reg))) + (count :scs (unsigned-reg))) (:arg-types unsigned-num positive-fixnum) (:results (result :scs (unsigned-reg))) (:result-types unsigned-num) @@ -887,12 +1157,12 @@ (inst sraw result digit count))) (define-vop (digit-lshr digit-ashr) - (:translate sb!bignum::%digit-logical-shift-right) + (:translate sb!bignum:%digit-logical-shift-right) (:generator 1 (inst srw result digit count))) (define-vop (digit-ashl digit-ashr) - (:translate sb!bignum::%ashl) + (:translate sb!bignum:%ashl) (:generator 1 (inst slw result digit count))) @@ -919,3 +1189,26 @@ (define-static-fun two-arg-and (x y) :translate logand) (define-static-fun two-arg-ior (x y) :translate logior) (define-static-fun two-arg-xor (x y) :translate logxor) +(define-static-fun two-arg-eqv (x y) :translate logeqv) + +(in-package "SB!C") + +(deftransform * ((x y) + ((unsigned-byte 32) (constant-arg (unsigned-byte 32))) + (unsigned-byte 32)) + "recode as shifts and adds" + (let ((y (lvar-value y))) + (multiple-value-bind (result adds shifts) + (ub32-strength-reduce-constant-multiply 'x y) + (cond + ((typep y '(signed-byte 16)) + ;; a mulli instruction has a latency of 5. + (when (> (+ adds shifts) 4) + (give-up-ir1-transform))) + (t + ;; a mullw instruction also has a latency of 5, plus two + ;; instructions (in general) to load the immediate into a + ;; register. + (when (> (+ adds shifts) 6) + (give-up-ir1-transform)))) + (or result 0))))