implement CEILING and FLOOR in terms of %CEILING and %FLOOR
authorNikodemus Siivola <nikodemus@sb-studio.net>
Fri, 5 Aug 2011 09:58:38 +0000 (12:58 +0300)
committerNikodemus Siivola <nikodemus@sb-studio.net>
Fri, 5 Aug 2011 13:11:06 +0000 (16:11 +0300)
  This allows transforms specific to CEILING and FLOOR fire first.

  If they fail, the fallback transforms to %CEILING or %FLOOR,
  respectively.

  They in turn are inlined, allowing the transforms for TRUNCATE
  to pick up the slack.

  This allows the new division -> multiplication transforms to fire
  for CEILING and FLOOR when SPACE > 1.

package-data-list.lisp-expr
src/code/numbers.lisp
src/compiler/fndb.lisp
src/compiler/srctran.lisp
tests/arith.pure.lisp

index 0af7bd7..8b80bf2 100644 (file)
@@ -1282,6 +1282,7 @@ is a good idea, but see SB-SYS re. blurring of boundaries."
                "%ATAN" "%ATAN2" "%ATANH"
                "%CALLER-FRAME"
                "%CALLER-PC"
+               "%CEILING"
                "%CHECK-BOUND"
                "%CHECK-GENERIC-SEQUENCE-BOUNDS"
                "%CHECK-VECTOR-SEQUENCE-BOUNDS"
@@ -1295,7 +1296,9 @@ is a good idea, but see SB-SYS re. blurring of boundaries."
                "%CONCATENATE-TO-STRING"
                "%COS" "%COS-QUICK"
                "%COSH" "%DATA-VECTOR-AND-INDEX" "%DEPOSIT-FIELD"
-               "%DOUBLE-FLOAT" "%DPB" "%EQL" "%EXP" "%EXPM1" "%FIND-POSITION"
+               "%DOUBLE-FLOAT" "%DPB" "%EQL" "%EXP" "%EXPM1"
+               "%FLOOR"
+               "%FIND-POSITION"
                "%FIND-POSITION-VECTOR-MACRO" "%FIND-POSITION-IF"
                "%FIND-POSITION-IF-VECTOR-MACRO" "%FIND-POSITION-IF-NOT"
                "%FIND-POSITION-IF-NOT-VECTOR-MACRO"
index 31455e8..ecf558d 100644 (file)
 ;;; Declare these guys inline to let them get optimized a little.
 ;;; ROUND and FROUND are not declared inline since they seem too
 ;;; obscure and too big to inline-expand by default. Also, this gives
-;;; the compiler a chance to pick off the unary float case. Similarly,
-;;; CEILING and FLOOR are only maybe-inline for now, so that the
-;;; power-of-2 CEILING and FLOOR transforms get a chance.
-#!-sb-fluid (declaim (inline rem mod fceiling ffloor ftruncate))
-(declaim (maybe-inline ceiling floor))
-
-(defun floor (number &optional (divisor 1))
-  #!+sb-doc
-  "Return the greatest integer not greater than number, or number/divisor.
-  The second returned value is (mod number divisor)."
+;;; the compiler a chance to pick off the unary float case.
+;;;
+;;; CEILING and FLOOR are implemented in terms of %CEILING and %FLOOR
+;;; if no better transform can be found: they aren't inline directly,
+;;; since we want to try a transform specific to them before letting
+;;; the transform for TRUNCATE pick up the slack.
+#!-sb-fluid (declaim (inline rem mod fceiling ffloor ftruncate %floor %ceiling))
+(defun %floor (number divisor)
   ;; If the numbers do not divide exactly and the result of
   ;; (/ NUMBER DIVISOR) would be negative then decrement the quotient
   ;; and augment the remainder by the divisor.
         (values (1- tru) (+ rem divisor))
         (values tru rem))))
 
-(defun ceiling (number &optional (divisor 1))
+(defun floor (number &optional (divisor 1))
   #!+sb-doc
-  "Return the smallest integer not less than number, or number/divisor.
-  The second returned value is the remainder."
+  "Return the greatest integer not greater than number, or number/divisor.
+  The second returned value is (mod number divisor)."
+  (%floor number divisor))
+
+(defun %ceiling (number divisor)
   ;; If the numbers do not divide exactly and the result of
   ;; (/ NUMBER DIVISOR) would be positive then increment the quotient
   ;; and decrement the remainder by the divisor.
         (values (+ tru 1) (- rem divisor))
         (values tru rem))))
 
+(defun ceiling (number &optional (divisor 1))
+  #!+sb-doc
+  "Return the smallest integer not less than number, or number/divisor.
+  The second returned value is the remainder."
+  (%ceiling number divisor))
+
 (defun round (number &optional (divisor 1))
   #!+sb-doc
   "Rounds number (or number/divisor) to nearest integer.
index 2086cf4..a735e43 100644 (file)
   (real &optional real) (values integer real)
   (movable foldable flushable explicit-check))
 
+(defknown (%floor %ceiling)
+  (real real) (values integer real)
+  (movable foldable flushable explicit-check))
+
 (defknown (mod rem) (real real) real
   (movable foldable flushable explicit-check))
 
index 1379d9f..3244cc9 100644 (file)
         `(- (ash x ,len))
         `(ash x ,len))))
 
+;;; These must come before the ones below, so that they are tried
+;;; first. Since %FLOOR and %CEILING are inlined, this allows
+;;; the general case to be handled by TRUNCATE transforms.
+(deftransform floor ((x y))
+  `(%floor x y))
+
+(deftransform ceiling ((x y))
+  `(%ceiling x y))
+
 ;;; If arg is a constant power of two, turn FLOOR into a shift and
 ;;; mask. If CEILING, add in (1- (ABS Y)), do FLOOR and correct a
 ;;; remainder.
index d570df2..b1ebdb2 100644 (file)
   (dolist (fun '(truncate floor ceiling mod rem))
     (let* ((foo (compile nil `(lambda (x)
                                 (declare (optimize (speed 3)
-                                                   (space 0)
+                                                   (space 1)
                                                    (compilation-speed 0))
                                          (type (unsigned-byte
                                                 ,sb-vm:n-word-bits) x))
         (dolist (fun '(truncate ceiling floor mod rem))
           (let ((foo (compile nil `(lambda (x)
                                      (declare (optimize (speed 3)
-                                                        (space 0)
+                                                        (space 1)
                                                         (compilation-speed 0))
                                               (type ,dividend-type x))
                                      (,fun x ,divisor)))))