home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcl / src-16f.lha / compiler / rt / arith.lisp < prev    next >
Encoding:
Text File  |  1991-11-06  |  26.6 KB  |  921 lines

  1. ;;; -*- Package: RT; Log: C.Log -*-
  2. ;;;
  3. ;;; **********************************************************************
  4. ;;; This code was written as part of the Spice Lisp project at
  5. ;;; Carnegie-Mellon University, and has been placed in the public domain.
  6. ;;; If you want to use this code or any part of Spice Lisp, please contact
  7. ;;; Scott Fahlman (FAHLMAN@CMUC). 
  8. ;;; **********************************************************************
  9. ;;;
  10. ;;; $Header: arith.lisp,v 1.10 91/06/13 16:37:48 wlott Exp $
  11. ;;;
  12. ;;; This file contains the VM definition arithmetic VOPs for the IBM RT.
  13. ;;;
  14. ;;; Written by Rob MacLachlan
  15. ;;;
  16. ;;; Converted by Bill Chiles.
  17. ;;;
  18.  
  19. (in-package "RT")
  20.  
  21.  
  22.  
  23. ;;;; Unary operations.
  24.  
  25. (define-vop (fixnum-unop)
  26.   (:args (x :scs (any-reg)))
  27.   (:results (res :scs (any-reg)))
  28.   (:note "inline fixnum arithmetic")
  29.   (:arg-types tagged-num)
  30.   (:result-types tagged-num)
  31.   (:policy :fast-safe))
  32.  
  33. (define-vop (signed-unop)
  34.   (:args (x :scs (signed-reg)))
  35.   (:results (res :scs (signed-reg)))
  36.   (:note "inline (signed-byte 32) arithmetic")
  37.   (:arg-types signed-num)
  38.   (:result-types signed-num)
  39.   (:policy :fast-safe))
  40.  
  41. (define-vop (fast-negate/fixnum fixnum-unop)
  42.   (:translate %negate)
  43.   (:generator 1
  44.     (inst neg res x)))
  45.  
  46. (define-vop (fast-negate/signed signed-unop)
  47.   (:translate %negate)
  48.   (:generator 2
  49.     (inst neg res x)))
  50.  
  51. (define-vop (fast-lognot/fixnum fixnum-unop)
  52.   (:temporary (:scs (any-reg) :type fixnum :to (:result 0) :target res)
  53.           temp)
  54.   (:translate lognot)
  55.   (:generator 2
  56.     (inst li temp (fixnum -1))
  57.     (inst x temp x)
  58.     (move res temp)))
  59.  
  60. (define-vop (fast-lognot/signed signed-unop)
  61.   (:translate lognot)
  62.   (:generator 1
  63.     (inst not res x)))
  64.  
  65.  
  66.  
  67. ;;;; Binary fixnum operations (+, -, LOGIOR, LOGAND, LOGXOR).
  68.  
  69. ;;; Assume that any constant operand is the second arg...
  70.  
  71. (define-vop (fast-fixnum-binop)
  72.   (:args (x :target r :scs (any-reg))
  73.      (y :scs (any-reg immediate) :to :save))
  74.   (:arg-types tagged-num tagged-num)
  75.   (:temporary (:scs (any-reg)) temp)
  76.   (:results (r :scs (any-reg)))
  77.   (:result-types tagged-num)
  78.   (:note "inline fixnum arithmetic")
  79.   (:effects)
  80.   (:affected)
  81.   (:policy :fast-safe))
  82.  
  83. (define-vop (fast-unsigned-binop)
  84.   (:args (x :target r :scs (unsigned-reg))
  85.      (y :scs (unsigned-reg immediate) :to :save))
  86.   (:arg-types unsigned-num unsigned-num)
  87.   (:temporary (:scs (any-reg)) temp)
  88.   (:results (r :scs (unsigned-reg)))
  89.   (:result-types unsigned-num)
  90.   (:note "inline (unsigned-byte 32) arithmetic")
  91.   (:effects)
  92.   (:affected)
  93.   (:policy :fast-safe))
  94.  
  95. (define-vop (fast-signed-binop)
  96.   (:args (x :target r :scs (signed-reg))
  97.      (y :scs (signed-reg immediate) :to :save))
  98.   (:arg-types signed-num signed-num)
  99.   (:temporary (:scs (any-reg)) temp)
  100.   (:results (r :scs (signed-reg)))
  101.   (:result-types signed-num)
  102.   (:note "inline (signed-byte 32) arithmetic")
  103.   (:effects)
  104.   (:affected)
  105.   (:policy :fast-safe))
  106.  
  107. (eval-when (compile eval)
  108.  
  109. (defmacro define-binop (translate cost op &body imm-body)
  110.   `(progn
  111.      (define-vop (,(intern (concatenate 'simple-string
  112.                     "FAST-"
  113.                     (string translate)
  114.                     "/FIXNUM=>FIXNUM"))
  115.           fast-fixnum-binop)
  116.        (:translate ,translate)
  117.        (:generator ,cost
  118.      (sc-case y
  119.        (any-reg
  120.         (move r x)
  121.         (inst ,op r y))
  122.        (immediate
  123.         (let ((value (fixnum (tn-value y))))
  124.           ,@imm-body)))))
  125.      (define-vop (,(intern (concatenate 'simple-string
  126.                     "FAST-"
  127.                     (string translate)
  128.                     "/SIGNED=>SIGNED"))
  129.           fast-signed-binop)
  130.        (:translate ,translate)
  131.        (:generator ,(1+ cost)
  132.      (sc-case y
  133.        (signed-reg
  134.         (move r x)
  135.         (inst ,op r y))
  136.        (immediate
  137.         (let ((value (tn-value y)))
  138.           ,@imm-body)))))
  139.      (define-vop (,(intern (concatenate 'simple-string
  140.                     "FAST-"
  141.                     (string translate)
  142.                     "/UNSIGNED=>UNSIGNED"))
  143.           fast-unsigned-binop)
  144.        (:translate ,translate)
  145.        (:generator ,(1+ cost)
  146.      (sc-case y
  147.        (unsigned-reg
  148.         (move r x)
  149.         (inst ,op r y))
  150.        (immediate
  151.         (let ((value (tn-value y)))
  152.           ,@imm-body)))))))
  153.  
  154. ) ;EVAL-WHEN
  155.  
  156.  
  157. (define-binop + 3 a
  158.   (cond ((typep value '(signed-byte 16))
  159.      (inst a r x value))
  160.     (t
  161.      (move r x)
  162.      (inst li temp value)
  163.      (inst a r temp))))
  164.  
  165. (define-binop - 3 s
  166.   (cond ((typep value '(signed-byte 16))
  167.      (inst s r x value))
  168.     (t
  169.      (move r x)
  170.      (inst li temp value)
  171.      (inst s r temp))))
  172.  
  173. (define-binop logior 2 o
  174.   (let ((low (ldb (byte 16 0) value))
  175.     (high (ldb (byte 16 16) value)))
  176.     (cond ((zerop value)
  177.        (move r x))
  178.       ((zerop low)
  179.        (inst oiu r x high))
  180.       ((zerop high)
  181.        (inst oil r x low))
  182.       (t
  183.        (inst oil r x low)
  184.        (inst oiu r r high)))))
  185.  
  186. (define-binop logxor 2 x
  187.   (let ((low (ldb (byte 16 0) value))
  188.     (high (ldb (byte 16 16) value)))
  189.     (cond ((zerop value)
  190.        (move r x))
  191.       ((zerop low)
  192.        (inst xiu r x high))
  193.       ((zerop high)
  194.        (inst xil r x low))
  195.       (t
  196.        (inst xil r x low)
  197.        (inst xiu r r high)))))
  198.  
  199. (define-binop logand 1 n
  200.   (let ((low (ldb (byte 16 0) value))
  201.     (high (ldb (byte 16 16) value)))
  202.     (cond ((= low high #xFFFF)
  203.        (move r x))
  204.       ((zerop low)
  205.        (inst niuz r x high))
  206.       ((= low #xFFFF)
  207.        (inst niuo r x high))
  208.       ((zerop high)
  209.        (inst nilz r x low))
  210.       ((= high #xFFFF)
  211.        (inst nilo r x low))
  212.       (t
  213.        (inst nilo r x low)
  214.        (inst niuo r r high)))))
  215.  
  216.  
  217.  
  218. ;;;; Binary fixnum operations.
  219.  
  220. (define-vop (fast-ash)
  221.   (:note "inline ASH")
  222.   (:args (number :scs (signed-reg unsigned-reg) :to (:result 0) :target result)
  223.      (amount-arg :scs (signed-reg immediate) :target amount))
  224.   (:arg-types (:or signed-num unsigned-num) signed-num)
  225.   (:results (result :scs (signed-reg unsigned-reg)))
  226.   (:result-types (:or signed-num unsigned-num))
  227.   (:translate ash)
  228.   (:policy :fast-safe)
  229.   (:temporary (:sc non-descriptor-reg :from (:argument 1)) amount)
  230.   (:generator 12
  231.     (sc-case amount-arg
  232.       (signed-reg
  233.        (let ((positive (gen-label))
  234.          (shift-right (gen-label))
  235.          (done (gen-label)))
  236.      ;; Copy the amount and check to see if it's positive.
  237.      (inst oil amount amount-arg 0)
  238.      (inst bnc :lt positive)
  239.  
  240.      ;; We want to shift to the right, so make the amount positive.
  241.      (inst neg amount)
  242.      (inst c amount 32)
  243.      ;; If less than 32, do the shifting.
  244.      (inst bc :lt shift-right)
  245.      ;; 32 or greater, we just shift by 31.
  246.      (inst li amount 31)
  247.      (emit-label shift-right)
  248.      (move result number)
  249.      (inst bx done)
  250.      (sc-case number
  251.        (signed-reg
  252.         (inst sar result amount))
  253.        (unsigned-reg
  254.         (inst sr result amount)))
  255.  
  256.      (emit-label positive)
  257.      ;; The result-type assures us that this shift will not overflow.
  258.      (move result number)
  259.      (inst sl result amount)
  260.  
  261.      (emit-label done)))
  262.  
  263.       (immediate
  264.        (let ((amount (tn-value amount-arg)))
  265.      (cond ((minusp amount)
  266.         (sc-case number
  267.           (unsigned-reg
  268.            (move result number)
  269.            (inst sr result (min (- amount) 31)))
  270.           (t
  271.            (move result number)
  272.            (inst sar result (min (- amount) 31)))))
  273.            (t
  274.         (move result number)
  275.         (inst sl result (min amount 31)))))))))
  276.  
  277.  
  278. ;;; SIGNED-BYTE-32-LEN -- VOP.
  279. ;;;
  280. ;;; Common Lisp INTEGER-LENGTH.  Due to the definition of this operation,
  281. ;;;    (integer-length x) == (integer-length (lognot x)).
  282. ;;; We determine the result by using the RT's count-leading-zeros which only
  283. ;;; works on the zeros in the lower half of a word, so we have to use it on
  284. ;;; the upperhalf and lowerhalf of number separately and do a little addition
  285. ;;; (actually, subtraction from the right values) to get the length.
  286. ;;;
  287. (define-vop (signed-byte-32-len)
  288.   (:translate integer-length)
  289.   (:note "inline (signed-byte 32) integer-length")
  290.   (:policy :fast-safe)
  291.   (:args (arg :scs (signed-reg)))
  292.   (:arg-types signed-num)
  293.   (:results (res :scs (unsigned-reg)))
  294.   (:result-types positive-fixnum)
  295.   (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) number)
  296.   (:temporary (:scs (non-descriptor-reg) :from (:eval 0)) temp)
  297.   (:generator 16
  298.     (let ((upper-not-zero (gen-label))
  299.       (count (gen-label)))
  300.       ;; Move arg and tell us if number is positive.
  301.       (inst oil number arg 0)
  302.       (inst bnc :lt count)
  303.       ;; Number is negative, so logically negate it to compute length.
  304.       (inst not number)
  305.       (emit-label count)
  306.       ;; Shift the upperhalf down and see if there are any 1's in it.
  307.       (move temp number)
  308.       (inst sr temp 16)
  309.       (inst bncx :eq upper-not-zero)
  310.       (inst li res 32)
  311.       ;; Upper half is all 0's, so get ready to subtract leading 0's in
  312.       ;; the lowerhalf from 16 to determine integer length.
  313.       (inst li res 16)
  314.       (move temp number)
  315.       (emit-label upper-not-zero)
  316.       ;; Here temp contains the upperhalf if not all 0's or the lowerhalf.
  317.       ;; Res contains the appropriate value (32 or 16) from which to subtract
  318.       ;; the number of leading 0's in temp to determine integer length.
  319.       (inst clz temp)
  320.       (inst s res temp))))
  321.  
  322. ;;; UNSIGNED-BYTE-32-COUNT -- VOP.
  323. ;;;
  324. ;;; To count the 1's in number, count how many times you can do the following:
  325. ;;;    AND number and the result of subtracting 1 from number.
  326. ;;;    Set number to the result of the AND operation.
  327. ;;; This subtract and AND clears the lowest 1 in number, so when number becomes
  328. ;;; zero, you're done.
  329. ;;;
  330. (define-vop (unsigned-byte-32-count)
  331.   (:translate logcount)
  332.   (:note "inline (unsigned-byte 32) logcount")
  333.   (:policy :fast-safe)
  334.   (:args (arg :scs (unsigned-reg)))
  335.   (:arg-types unsigned-num)
  336.   (:results (res :scs (any-reg)))
  337.   (:result-types positive-fixnum)
  338.   (:temporary (:scs (non-descriptor-reg)) number temp)
  339.   (:generator 14
  340.     (let ((loop (gen-label))
  341.       (done (gen-label)))
  342.       ;; Move arg and tell us if number is zero, in which case res is 0.
  343.       (inst oil number arg 0)
  344.       (inst bcx :eq done)
  345.       (inst li res 0)
  346.       ;; Count 1's in number.
  347.       (emit-label loop)
  348.       (move temp number)
  349.       (inst s temp 1)
  350.       (inst n number temp)
  351.       (inst bncx :eq loop)
  352.       (inst a res (fixnum 1))
  353.       ;; We're done and res already has result.
  354.       (emit-label done))))      
  355.  
  356.  
  357.  
  358. ;;;; Binary conditional VOPs:
  359.  
  360. (define-vop (fast-conditional)
  361.   (:conditional)
  362.   (:info target not-p)
  363.   (:effects)
  364.   (:affected)
  365.   (:policy :fast-safe))
  366.  
  367. (define-vop (fast-conditional/fixnum fast-conditional)
  368.   (:args (x :scs (any-reg))
  369.      (y :scs (any-reg)))
  370.   (:arg-types tagged-num tagged-num)
  371.   (:note "inline fixnum comparison"))
  372.  
  373. (define-vop (fast-conditional-c/fixnum fast-conditional/fixnum)
  374.   (:args (x :scs (any-reg)))
  375.   ;; Leave room in the signed field for
  376.   (:arg-types tagged-num (:constant (signed-byte 14)))
  377.   (:info target not-p y))
  378.  
  379. (define-vop (fast-conditional/signed fast-conditional)
  380.   (:args (x :scs (signed-reg))
  381.      (y :scs (signed-reg)))
  382.   (:arg-types signed-num signed-num)
  383.   (:note "inline (signed-byte 32) comparison"))
  384.  
  385. (define-vop (fast-conditional-c/signed fast-conditional/signed)
  386.   (:args (x :scs (signed-reg)))
  387.   (:arg-types signed-num (:constant (signed-byte 16)))
  388.   (:info target not-p y))
  389.  
  390. (define-vop (fast-conditional/unsigned fast-conditional)
  391.   (:args (x :scs (unsigned-reg))
  392.      (y :scs (unsigned-reg)))
  393.   (:arg-types unsigned-num unsigned-num)
  394.   (:note "inline (unsigned-byte 32) comparison"))
  395.  
  396. (define-vop (fast-conditional-c/unsigned fast-conditional/unsigned)
  397.   (:args (x :scs (unsigned-reg)))
  398.   (:arg-types unsigned-num (:constant (unsigned-byte 15)))
  399.   (:info target not-p y))
  400.  
  401.  
  402. (defmacro define-conditional-vop (translate &rest generator)
  403.   `(progn
  404.      ,@(mapcar #'(lambda (suffix cost signed)
  405.            (unless (and (member suffix '(/fixnum -c/fixnum))
  406.                 (eq translate 'eql))
  407.              `(define-vop (,(intern (format nil "~:@(FAST-IF-~A~A~)"
  408.                             translate suffix))
  409.                    ,(intern
  410.                      (format nil "~:@(FAST-CONDITIONAL~A~)"
  411.                          suffix)))
  412.             (:translate ,translate)
  413.             (:generator ,cost
  414.               (let* ((signed ,signed)
  415.                  (-c/fixnum ,(eq suffix '-c/fixnum))
  416.                  (y (if -c/fixnum (fixnum y) y)))
  417.                 ,@generator)))))
  418.            '(/fixnum -c/fixnum /signed -c/signed /unsigned -c/unsigned)
  419.            ;; All these really take six cycles, but we decrease the -c/...
  420.            ;; cost to prefer these VOPs since we avoid doing
  421.            ;; load-immediates.  Then the first two are decreased by by one
  422.            ;; more to prefer comparing the fixnum representation directly.
  423.            '(5 4 6 5 6 5)
  424.            '(t t t t nil nil))))
  425.  
  426. (define-conditional-vop <
  427.   (if signed
  428.       (inst c x y)
  429.       (inst cl x y))
  430.   (if not-p
  431.       (inst bnc :lt target)
  432.       (inst bc :lt target)))
  433.  
  434. (define-conditional-vop >
  435.   (if signed
  436.       (inst c x y)
  437.       (inst cl x y))
  438.   (if not-p
  439.       (inst bnc :gt target)
  440.       (inst bc :gt target)))
  441.  
  442. ;;; This only handles EQL of restricted integers, so it's simple.
  443. ;;;
  444. (define-conditional-vop eql
  445.   (declare (ignore signed))
  446.   (inst c x y)
  447.   (if not-p
  448.       (inst bnc :eq target)
  449.       (inst bc :eq target)))
  450.  
  451.  
  452. ;;; EQL/FIXNUM is funny because the first arg can be of any type, not just a
  453. ;;; known fixnum.
  454. ;;;
  455.  
  456. (define-vop (fast-eql/fixnum fast-conditional)
  457.   (:args (x :scs (any-reg descriptor-reg))
  458.      (y :scs (any-reg)))
  459.   (:arg-types * tagged-num)
  460.   (:note "inline fixnum comparison")
  461.   (:translate eql)
  462.   (:ignore temp)
  463.   (:generator 4
  464.     (inst c x y)
  465.     (if not-p
  466.     (inst bnc :eq target)
  467.     (inst bc :eq target))))
  468.  
  469. (define-vop (fast-eql-c/fixnum fast-conditional/fixnum)
  470.   (:args (x :scs (any-reg descriptor-reg)))
  471.   (:arg-types * (:constant (signed-byte 14)))
  472.   (:info target not-p y)
  473.   (:translate eql)
  474.   (:generator 3
  475.     (inst c x (fixnum y))
  476.     (if not-p
  477.     (inst bnc :eq target)
  478.     (inst bc :eq target))))
  479.  
  480.  
  481.  
  482. ;;;; 32-bit logical operations
  483.  
  484. (define-vop (32bit-logical)
  485.   (:args (x :scs (unsigned-reg) :target r)
  486.      (y :scs (unsigned-reg)))
  487.   (:arg-types unsigned-num unsigned-num)
  488.   (:results (r :scs (unsigned-reg) :from (:argument 0)))
  489.   (:result-types unsigned-num)
  490.   (:policy :fast-safe))
  491.  
  492. (define-vop (32bit-logical-not 32bit-logical)
  493.   (:translate 32bit-logical-not)
  494.   (:args (x :scs (unsigned-reg)))
  495.   (:arg-types unsigned-num)
  496.   (:generator 1
  497.     (inst not r x)))
  498.  
  499. (define-vop (32bit-logical-and 32bit-logical)
  500.   (:translate 32bit-logical-and)
  501.   (:generator 1
  502.     (move r x)
  503.     (inst n r y)))
  504.  
  505. (deftransform 32bit-logical-nand ((x y) (* *))
  506.   '(32bit-logical-not (32bit-logical-and x y)))
  507.  
  508. (define-vop (32bit-logical-or 32bit-logical)
  509.   (:translate 32bit-logical-or)
  510.   (:generator 1
  511.     (move r x)
  512.     (inst o r y)))
  513.  
  514. (deftransform 32bit-logical-nor ((x y) (* *))
  515.   '(32bit-logical-not (32bit-logical-or x y)))
  516.  
  517. (define-vop (32bit-logical-xor 32bit-logical)
  518.   (:translate 32bit-logical-xor)
  519.   (:generator 1
  520.     (move r x)
  521.     (inst x r y)))
  522.  
  523. (deftransform 32bit-logical-eqv ((x y) (* *))
  524.   '(32bit-logical-not (32bit-logical-xor x y)))
  525.  
  526. (deftransform 32bit-logical-andc1 ((x y) (* *))
  527.   '(32bit-logical-and (32bit-logical-not x) y))
  528.  
  529. (deftransform 32bit-logical-andc2 ((x y) (* *))
  530.   '(32bit-logical-and x (32bit-logical-not y)))
  531.  
  532. (deftransform 32bit-logical-orc1 ((x y) (* *))
  533.   '(32bit-logical-or (32bit-logical-not x) y))
  534.  
  535. (deftransform 32bit-logical-orc2 ((x y) (* *))
  536.   '(32bit-logical-or x (32bit-logical-not y)))
  537.  
  538. (define-vop (shift-towards-someplace)
  539.   (:policy :fast-safe)
  540.   (:args (num :scs (unsigned-reg) :target r :to (:eval 0))
  541.      (amount :scs (signed-reg) :target temp))
  542.   (:temporary (:scs (signed-reg) :from (:argument 1)) temp)
  543.   (:arg-types unsigned-num tagged-num)
  544.   (:results (r :scs (unsigned-reg)))
  545.   (:result-types unsigned-num))
  546.  
  547. (define-vop (shift-towards-start shift-towards-someplace)
  548.   (:translate shift-towards-start)
  549.   (:note "SHIFT-TOWARDS-START")
  550.   (:generator 1
  551.     (move temp amount)
  552.     (inst nilz temp #x1f)
  553.     (move r num)
  554.     (inst sl r temp)))
  555.  
  556. (define-vop (shift-towards-end shift-towards-someplace)
  557.   (:translate shift-towards-end)
  558.   (:note "SHIFT-TOWARDS-END")
  559.   (:generator 1
  560.     (move temp amount)
  561.     (inst nilz temp #x1f)
  562.     (move r num)
  563.     (inst sr r temp)))
  564.  
  565.  
  566.  
  567.  
  568. ;;;; Bignum stuff.
  569.  
  570. (define-vop (bignum-length get-header-data)
  571.   (:translate bignum::%bignum-length)
  572.   (:policy :fast-safe))
  573.  
  574. (define-vop (bignum-set-length set-header-data)
  575.   (:translate bignum::%bignum-set-length)
  576.   (:policy :fast-safe))
  577.  
  578. (define-vop (bignum-ref word-index-ref)
  579.   (:variant vm:bignum-digits-offset vm:other-pointer-type)
  580.   (:translate bignum::%bignum-ref)
  581.   (:results (value :scs (unsigned-reg)))
  582.   (:result-types unsigned-num))
  583.  
  584. (define-vop (bignum-set word-index-set)
  585.   (:variant vm:bignum-digits-offset vm:other-pointer-type)
  586.   (:translate bignum::%bignum-set)
  587.   (:args (object :scs (descriptor-reg))
  588.      (index :scs (any-reg immediate))
  589.      (value :scs (unsigned-reg)))
  590.   (:arg-types t positive-fixnum unsigned-num)
  591.   (:results (result :scs (unsigned-reg)))
  592.   (:result-types unsigned-num))
  593.  
  594. (define-vop (digit-0-or-plus)
  595.   (:translate bignum::%digit-0-or-plusp)
  596.   (:policy :fast-safe)
  597.   (:args (digit :scs (unsigned-reg)))
  598.   (:arg-types unsigned-num)
  599.   (:results (result :scs (descriptor-reg)))
  600.   (:generator 7
  601.     (let ((done (gen-label)))
  602.       (inst c digit 0)
  603.       (inst bcx :lt done)
  604.       (move result null-tn)
  605.       (load-symbol result 't)
  606.       (emit-label done))))
  607.  
  608. (define-vop (add-w/carry)
  609.   (:translate bignum::%add-with-carry)
  610.   (:policy :fast-safe)
  611.   (:args (a :scs (unsigned-reg) :target result)
  612.      (b :scs (unsigned-reg))
  613.      (carry-in :scs (any-reg)))
  614.   (:arg-types unsigned-num unsigned-num positive-fixnum)
  615.   (:results (result :scs (unsigned-reg) :from (:argument 0))
  616.         (carry :scs (unsigned-reg)))
  617.   (:result-types unsigned-num positive-fixnum)
  618.   (:temporary (:scs (non-descriptor-reg) :to (:argument 2)) temp)
  619.   (:generator 5
  620.     ;; Set the carry condition bit.
  621.     (inst a temp carry-in -1)
  622.     ;; Add A & B.
  623.     (move result a)
  624.     (inst ae result b)
  625.     ;; Set carry to the condition bit.
  626.     ;; Add zero to zero and see if we get a one.
  627.     (inst li carry 0)
  628.     (inst ae carry carry)))
  629.  
  630. (define-vop (sub-w/borrow)
  631.   (:translate bignum::%subtract-with-borrow)
  632.   (:policy :fast-safe)
  633.   (:args (a :scs (unsigned-reg) :target result)
  634.      (b :scs (unsigned-reg))
  635.      (borrow-in :scs (any-reg)))
  636.   (:arg-types unsigned-num unsigned-num positive-fixnum)
  637.   (:results (result :scs (unsigned-reg) :from (:argument 0))
  638.         (borrow :scs (unsigned-reg) :from :eval))
  639.   (:result-types unsigned-num positive-fixnum)
  640.   (:temporary (:scs (non-descriptor-reg)
  641.             :from (:argument 0) :to (:argument 2)) temp)
  642.   (:generator 5
  643.     (move result a)
  644.     ;; Set the carry condition bit.
  645.     ;; Borrow-in is zero if there was a borrow, one if there was no borrow.
  646.     ;; The RT has the same sense with its C0 condition bit.
  647.     (inst a temp borrow-in -1)
  648.     (inst se result b)
  649.     ;; Set borrow to 0 if the carry condition bit is zero, or to 1 otherwise.
  650.     (inst li borrow 0)
  651.     (inst ae borrow borrow)))
  652.  
  653. (define-vop (bignum-mult-and-add-3-arg)
  654.   (:translate bignum::%multiply-and-add)
  655.   (:policy :fast-safe)
  656.   (:vop-var vop)
  657.   (:args (x :scs (unsigned-reg))
  658.      (y :scs (unsigned-reg))
  659.      (carry-in :scs (unsigned-reg unsigned-stack) :to (:eval 1)))
  660.   (:arg-types unsigned-num unsigned-num unsigned-num)
  661.   (:temporary (:scs (unsigned-reg) :from (:eval 0)) temp)
  662.   (:temporary (:scs (unsigned-reg) :to (:result 0) :target high-res) high)
  663.   (:temporary (:scs (unsigned-reg) :from (:eval 0) :to (:result 1)
  664.             :target low-res) low)
  665.   (:results (high-res :scs (unsigned-reg))
  666.         (low-res :scs (unsigned-reg)))
  667.   (:result-types unsigned-num unsigned-num)
  668.   (:generator 76
  669.     ;; Do the multiply.
  670.     (unsigned-multiply x y high low)
  671.  
  672.     ;; Add the carry-in.
  673.     (sc-case carry-in
  674.       (unsigned-stack
  675.        (load-stack-tn temp carry-in vop)
  676.        (inst a low temp))
  677.       (unsigned-reg
  678.        (inst a low carry-in)))
  679.     (inst ae high 0)
  680.     (move high-res high)
  681.     (move low-res low)))
  682.  
  683. (define-vop (bignum-mult-and-add-4-arg)
  684.   (:translate bignum::%multiply-and-add)
  685.   (:vop-var vop)
  686.   (:policy :fast-safe)
  687.   (:args (x :scs (unsigned-reg))
  688.      (y :scs (unsigned-reg))
  689.      (prev :scs (unsigned-reg unsigned-stack) :to (:eval 1))
  690.      (carry-in :scs (unsigned-reg unsigned-stack) :to (:eval 1)))
  691.   (:arg-types unsigned-num unsigned-num unsigned-num unsigned-num)
  692.   (:temporary (:scs (unsigned-reg) :from (:eval 0)) temp)
  693.   (:temporary (:scs (unsigned-reg) :to (:result 0) :target high-res) high)
  694.   (:temporary (:scs (unsigned-reg) :from (:eval 0) :to (:result 1)
  695.             :target low-res) low)
  696.   (:results (high-res :scs (unsigned-reg))
  697.         (low-res :scs (unsigned-reg)))
  698.   (:result-types unsigned-num unsigned-num)
  699.   (:generator 81
  700.     ;; Do the multiply.
  701.     (unsigned-multiply x y high low)
  702.  
  703.     ;; Add the carry-in.
  704.     (sc-case carry-in
  705.       (unsigned-stack
  706.        (load-stack-tn temp carry-in vop)
  707.        (inst a low temp))
  708.       (unsigned-reg
  709.        (inst a low carry-in)))
  710.     (inst ae high 0)
  711.     
  712.     ;; Add in digit from accumulating result.
  713.     (sc-case carry-in
  714.       (unsigned-stack
  715.        (load-stack-tn temp prev vop)
  716.        (inst a low temp))
  717.       (unsigned-reg
  718.        (inst a low prev)))
  719.     (inst ae high 0)
  720.     (move high-res high)
  721.     (move low-res low)))
  722.  
  723. (define-vop (bignum-mult)
  724.   (:translate bignum::%multiply)
  725.   (:policy :fast-safe)
  726.   (:args (x :scs (unsigned-reg))
  727.      (y :scs (unsigned-reg)))
  728.   (:arg-types unsigned-num unsigned-num)
  729.   (:results (high :scs (unsigned-reg) :from :load)
  730.         (low :scs (unsigned-reg)))
  731.   (:result-types unsigned-num unsigned-num)
  732.   (:generator 74
  733.     ;; Do the multiply.
  734.     (unsigned-multiply x y high low)))
  735.  
  736. ;;; UNSIGNED-MULTIPLY -- Internal.
  737. ;;;
  738. ;;; The RT has a signed multiply.  To unsigned-multiply bignum digits, we use
  739. ;;; the following identity:
  740. ;;;    signed-interpretation
  741. ;;;       =  unsigned-interpretation  -  (sign-bit)(2^32)
  742. ;;;    ==>
  743. ;;;    ui = si + (sb)(2^32)
  744. ;;; This gives us the following equation:
  745. ;;;    (ui1) (ui2)  =  [si1 + (sb1)(2^32)] [si2 + (sb2)(2^32)]
  746. ;;;    (ui1) (ui2)  =  (si1) (si2)
  747. ;;;                  + [(sb1)(si2) + (sb2)(si1)] (2^32)
  748. ;;;              + (sb1)(sb2)(2^32)
  749. ;;; Inspection and the fact that the result must fit into 64 bits reveals that
  750. ;;; the third time can always be ignored.
  751. ;;;
  752. (defun unsigned-multiply (x y high low)
  753.   ;; Setup system register for multiply.
  754.   (inst mtmqscr x)
  755.   
  756.   ;; Do the multiply.
  757.   ;; Subtract high from high to set it to zero and to set the C0 condition
  758.   ;; bit appropriately for the m instruction.
  759.   (inst s high high)
  760.   (dotimes (i 16)
  761.     (inst m high y))
  762.   ;; Adjust high word of result for unsigned multiply.
  763.   ;; If x is negative, add in y.  If y is negative, add in x.
  764.   (let ((x-pos (gen-label))
  765.     (y-pos (gen-label)))
  766.     (inst c x 0)
  767.     (inst bnc :lt x-pos)
  768.     (inst a high y)
  769.     (emit-label x-pos)
  770.     (inst c y 0)
  771.     (inst bnc :lt y-pos)
  772.     (inst a high x)
  773.     (emit-label y-pos))
  774.   
  775.   ;; Get the low 32 bits of the product.
  776.   (inst mfmqscr low))
  777.  
  778.  
  779. (define-vop (bignum-lognot)
  780.   (:translate bignum::%lognot)
  781.   (:policy :fast-safe)
  782.   (:args (x :scs (unsigned-reg)))
  783.   (:arg-types unsigned-num)
  784.   (:results (r :scs (unsigned-reg)))
  785.   (:result-types unsigned-num)
  786.   (:generator 1
  787.     (inst not r x)))
  788.  
  789. (define-vop (fixnum-to-digit)
  790.   (:translate bignum::%fixnum-to-digit)
  791.   (:policy :fast-safe)
  792.   (:args (fixnum :scs (any-reg) :target digit))
  793.   (:arg-types tagged-num)
  794.   (:results (digit :scs (unsigned-reg)))
  795.   (:result-types unsigned-num)
  796.   (:generator 1
  797.     (move digit fixnum)
  798.     (inst sar digit 2)))
  799.  
  800. ;;; BIGNUM-FLOOR -- VOP.
  801. ;;;
  802. ;;; The way the bignum code uses this allows us to ignore dividing by 0, 1, or
  803. ;;; -1.  Furthermore, we always divided a positive high:low value by a positive
  804. ;;; divisor value.  This means we don't have to worry about using the RT's
  805. ;;; signed divide instruction to get an unsigned division result.
  806. ;;;
  807. ;;; We are going to copy the GENERIC-TRUNCATE assembly routine to implement
  808. ;;; this since FLOOR and TRUNCATE return the same values for positive
  809. ;;; arguments.  However, we do modify it slightly to make use of the positive
  810. ;;; nature of the arguments.
  811. ;;;
  812. (define-vop (bignum-floor)
  813.   (:translate bignum::%floor)
  814.   (:policy :fast-safe)
  815.   (:args (dividend-high :scs (unsigned-reg) :target rem)
  816.      (dividend-low :scs (unsigned-reg))
  817.      (divisor :scs (unsigned-reg) :to (:eval 1)))
  818.   (:arg-types unsigned-num unsigned-num unsigned-num)
  819.   (:results (quo :scs (unsigned-reg))
  820.         (rem :scs (unsigned-reg) :from (:eval 0)))
  821.   (:result-types unsigned-num unsigned-num)
  822.   (:generator 44
  823.     (inst mtmqscr dividend-low)
  824.     (move rem dividend-high)
  825.     (dotimes (i 32)
  826.       (inst d rem divisor))
  827.     ;; Check preliminary remainder by considering signs of rem and divisor.
  828.     ;; This is an extra step to account for the non-restoring divide-step instr.
  829.     ;; We don't actually have to check this since the d instruction set :c0
  830.     ;; when the signs of rem and divisor are the same.
  831.     (let ((rem-okay (gen-label)))
  832.       (inst bc :c0 rem-okay)
  833.       (inst a rem divisor)
  834.       (emit-label rem-okay))
  835.  
  836.     (let ((move-results (gen-label)))
  837.       ;; The RT gives us some random division concept, but we're writing
  838.       ;; TRUNCATE.  The fixup involves adding one to the quotient and
  839.       ;; subtracting the divisor from the remainder under certain
  840.       ;; circumstances (for this VOP, as opposed to the assembly routine,
  841.       ;; this boils down to one test):
  842.       ;;
  843.       ;; IF the remainder is equal to the divisor, we can obviously take
  844.       ;; one more divisor out of the dividend, so do it.
  845.       (inst c rem divisor)
  846.       (inst bnc :eq move-results) ;Just fall through to do it.
  847.  
  848.       ;; Add 1 to quotient and subtract divisor from remainder.
  849.       (inst mfmqscr quo)
  850.       (inst inc quo 1)
  851.       (inst s rem divisor)
  852.       
  853.       (emit-label move-results))
  854.  
  855.     (inst mfmqscr quo)))
  856.  
  857.  
  858. ;;; SIGNIFY-DIGIT -- VOP.
  859. ;;;
  860. ;;; This is supposed to make digit into a fixnum which is signed.  We just
  861. ;;; move it here, letting the compiler's operand motion stuff make this
  862. ;;; result into a fixnum.
  863. ;;;
  864. (define-vop (signify-digit)
  865.   (:translate bignum::%fixnum-digit-with-correct-sign)
  866.   (:policy :fast-safe)
  867.   (:args (digit :scs (unsigned-reg) :target res))
  868.   (:arg-types unsigned-num)
  869.   (:results (res :scs (signed-reg)))
  870.   (:result-types signed-num)
  871.   (:generator 1
  872.     (move res digit)))
  873.  
  874. (define-vop (digit-ashr)
  875.   (:translate bignum::%ashr)
  876.   (:policy :fast-safe)
  877.   (:args (digit :scs (unsigned-reg) :target result)
  878.      (count :scs (unsigned-reg immediate)))
  879.   (:arg-types unsigned-num positive-fixnum)
  880.   (:results (result :scs (unsigned-reg) :from (:argument 0)))
  881.   (:result-types unsigned-num)
  882.   (:generator 2
  883.     (move result digit)
  884.     (inst sar result
  885.       (sc-case count
  886.         (unsigned-reg count)
  887.         (immediate (tn-value count))))))
  888.  
  889. (define-vop (digit-lshr digit-ashr)
  890.   (:translate bignum::%digit-logical-shift-right)
  891.   (:generator 2
  892.     (move result digit)
  893.     (inst sr result
  894.       (sc-case count
  895.         (unsigned-reg count)
  896.         (immediate (tn-value count))))))
  897.  
  898. (define-vop (digit-ashl digit-ashr)
  899.   (:translate bignum::%ashl)
  900.   (:generator 2
  901.     (move result digit)
  902.     (inst sl result
  903.       (sc-case count
  904.         (unsigned-reg count)
  905.         (immediate (tn-value count))))))
  906.  
  907.  
  908.  
  909. ;;;; Static functions.
  910.  
  911. (define-static-function two-arg-gcd (x y) :translate gcd)
  912. (define-static-function two-arg-lcm (x y) :translate lcm)
  913.  
  914. (define-static-function two-arg-/ (x y) :translate /)
  915.  
  916. (define-static-function %negate (x) :translate %negate)
  917.  
  918. (define-static-function two-arg-and (x y) :translate logand)
  919. (define-static-function two-arg-ior (x y) :translate logior)
  920. (define-static-function two-arg-xor (x y) :translate logxor)
  921.