From 0b79d8fa3e2a1c2ba30fac3828215d74351ff40e Mon Sep 17 00:00:00 2001 From: Nikodemus Siivola Date: Fri, 5 Aug 2011 12:58:38 +0300 Subject: [PATCH] implement CEILING and FLOOR in terms of %CEILING and %FLOOR 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 | 5 ++++- src/code/numbers.lisp | 33 ++++++++++++++++++++------------- src/compiler/fndb.lisp | 4 ++++ src/compiler/srctran.lisp | 9 +++++++++ tests/arith.pure.lisp | 4 ++-- 5 files changed, 39 insertions(+), 16 deletions(-) diff --git a/package-data-list.lisp-expr b/package-data-list.lisp-expr index 0af7bd7..8b80bf2 100644 --- a/package-data-list.lisp-expr +++ b/package-data-list.lisp-expr @@ -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" diff --git a/src/code/numbers.lisp b/src/code/numbers.lisp index 31455e8..ecf558d 100644 --- a/src/code/numbers.lisp +++ b/src/code/numbers.lisp @@ -593,16 +593,14 @@ ;;; 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. @@ -614,10 +612,13 @@ (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. @@ -629,6 +630,12 @@ (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. diff --git a/src/compiler/fndb.lisp b/src/compiler/fndb.lisp index 2086cf4..a735e43 100644 --- a/src/compiler/fndb.lisp +++ b/src/compiler/fndb.lisp @@ -319,6 +319,10 @@ (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)) diff --git a/src/compiler/srctran.lisp b/src/compiler/srctran.lisp index 1379d9f..3244cc9 100644 --- a/src/compiler/srctran.lisp +++ b/src/compiler/srctran.lisp @@ -3186,6 +3186,15 @@ `(- (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. diff --git a/tests/arith.pure.lisp b/tests/arith.pure.lisp index d570df2..b1ebdb2 100644 --- a/tests/arith.pure.lisp +++ b/tests/arith.pure.lisp @@ -414,7 +414,7 @@ (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)) @@ -446,7 +446,7 @@ (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))))) -- 1.7.10.4