;;; -*- Mode:Common-Lisp; Package:Compiler2; Base:10 -*- ;;; RESTRICTED RIGHTS LEGEND ;;;Use, duplication, or disclosure by the Government is subject to ;;;restrictions as set forth in subdivision (c)(1)(ii) of the Rights in ;;;Technical Data and Computer Software clause at 52.227-7013. ;;; ;;; TEXAS INSTRUMENTS INCORPORATED. ;;; P.O. BOX 2909 ;;; AUSTIN, TEXAS 78769 ;;; MS 2151 ;;; ;;; Copyright (C) 1984-1989 Texas Instruments Incorporated. All rights reserved. ;;; Copyright (C) 1980 Massachusetts Institute of Technology ;;;; *-----------------------------------------------------------* ;;;; | -- TI Explorer Lisp Compiler -- | ;;;; | This file contains the pass 1 optimizers for operations | ;;;; | on numbers and characters. | ;;;; *-----------------------------------------------------------* ;;; Feb. 1984 - Version 98 from MIT via LMI. [file "SYS;QCOPT"] ;;; July 1984 - TI modifications to do constant folding bottom-up (i.e., ;;; after P1 instead of before), to do folding on conditional ;;; expressions, and various other improvements. ;;; Also fixed bug 585 - warning on DECLARE inside DO. ;;; 07/25/84 - From MIT patch 98.33, fix CALL-TO-MULTIPLE-VALUE-LIST to recognize CLI:LAMBDA. ;;; 08/01/84 DNG - From MIT patch 98.40, fix to optimize CLI:// and CLI:ATAN. ;;; 08/06/84 DNG - From MIT patch 98.47, add MAKE-OBSOLETE of CATCH and THROW, ;;; optimize CLI:CATCH to *CATCH and CLI:THROW to *THROW, fix ;;; optimization of relational with one argument to evaluate the ;;; argument for side-effects, add new functions EQL-EQ and ;;; MEMBER-EQL-MEMQ, replace TRY-TO-USE-SIMPLE-MAKE-ARRAY, add ;;; style checkers for APPEND and SUBST. ;;; 08/07/84 DNG - From MIT patch 98.57, add optimizer for MAKE-STRING, ;;; update FLOAT-OPTIMIZER, and modify MEMQ-EQ. ;;; 09/05/84 DNG - Assorted improvements. ;;; 12/27/84 DNG - Created new functions ARGS-SAME and LOGAND-OPT; use SI:EVAL1 ;;; instead of EVAL to fix LET-IF in Common Lisp mode. ;;; 1/04/85 DNG - More on CLI:MEMBER; optimize (LENGTH (LIST ...)); ;;; use %DUP for multiply by 2 or exponent 2. ;;; 2/05/85 DNG - Created new function INC-VAR-USE. ;;; 2/06/85 DNG - Provide for constant folding on some more functions. ;;; 3/07/85 DNG - Updates to INTERNAL-=-OPTIMIZER, INC-VAR-USE, and ADD-1-OPT. ;;; 4/12/85 DNG - Fix numeric optimizations for bugs [1223] and [1185]. ;;; 4/23/85 DNG - Fix a few more cases of bugs [1185] and [1574]. ;;;------------------ The following done after Explorer release 1.0 ------ ;;; 6/25/85 DNG - Fix to optimize CHAR< etc. like their numeric counterparts; ;;; optimize comparison with three arbitrary arguments; ;;; change 2-argument NCONC to *NCONC and APPEND to *APPEND. ;;; 6/26/85 DNG - Expand TRIVIAL-FORM-P inline in NO-SIDE-EFFECTS-P. ;;; 7/26/85 DNG - For release 3, split file QCOPT into P1OPT, P1STYLE, and MACLISP. ;;; Removed support for function names in keyword package. ;;; 8/17/85 DNG - Moved *LEXPR, *EXPR, and *FEXPR to MACLISP file. ;;; 8/19/85 DNG - New functions INDEPENDENT-EXPRESSIONS-P and STORE-TO-SET. ;;; 11/12/85 DNG - This file separated from P1OPT. ;;; 11/12/85 DNG - Optimize CLI:FLOAT. ;;; 12/02/85 DNG - Do constant folding for TAN and hyperbolic functions; ;;; Inhibit (* x 0) ==> 0 except in an inline expansion. ;;; 4/06/86 DNG - Converted from Zetalisp to Common Lisp. ;;; 4/21/86 DNG - Constant folding on INTEGERP and FIXP. ;;; 5/12/86 DNG - Use new function FOLD-TYPE-PREDICATE. ;;; 8/14/86 DNG - Remove use of old two-argument function names *PLUS etc. ;;; 10/15/86 DNG - Enable constant folding for some more character functions. ;;; 11/13/86 DNG - Enable constant folding for %LOGLDB and %LOGDPB. ;;; 12/08/86 DNG - Optimize (CHAR-NOT-EQUAL a b) ==> (NOT (INTERNAL-CHAR-EQUAL a b)). ;;; 1/15/87 DNG - Fix optimization of FLOAT for double precision. ;;; 1/21/87 DNG - Enable constant folding for STRING-CHAR-P, SI:FAT-STRING-CHAR-P, and LOWER-CASE-P. ;;; 3/20/87 DNG - Enable constant folding for COERCE-TO-CHARACTER and COERCE-TO-...-FLOAT. ;;; 11/14/88 clm - Added new post-opt to handle cases like (/ x y z v) so that a newly consed %DIV form ;;; will pass back through ARITHEXP for the arguments will be handled correctly. ;;;; ================================== ;;;; Utility functions ;;;; ================================== (DEFUN QUOTE-NUMBER ( X ) ; return number from form (QUOTE number) , else NIL (IF (AND (CONSP X) (EQ (FIRST X) 'QUOTE) (NUMBERP (SECOND X)) ) (SECOND X) NIL )) (DEFUN QUOTE-ZERO-P ( ARG ) ; does ARG equal '0 ? (AND (CONSP ARG) (EQ (FIRST ARG) 'QUOTE) (NUMBERP (SECOND ARG)) (ZEROP (SECOND ARG)) ) ) ;;;; ================================== ;;;; Express multi-argument arithmetic functions in terms of two-argument versions. ;;;; ================================== (DEFUN ARITHEXP (X) ;; 8/1/84 DNG - Adapted from MIT patch 98.40, add CLI:/ and %DIV. ;; 4/6/86 DNG - Modernized coding style. ;;8/14/86 DNG - Eliminated distinction between 2-arg and multi-arg function names; ;; use FOLD-CONSTANTS to get the value for the no-arg case. (LET ((L (LENGTH (CDR X))) (OP (CAR X))) (COND ((EQ OP 'CLI:/) (SETQ OP '%DIV)) ((EQ OP 'GLOBAL:/) (SETQ OP 'QUOTIENT))) (COND ((= 0 L) (FOLD-CONSTANTS X)) ((= L 1) (COND ((EQ OP '-) (LIST 'MINUS (SECOND X))) ((MEMBER (CAR X) '(GLOBAL:/ CLI:/ %DIV) :TEST #'EQ) ; but not QUOTIENT! (LIST OP '(QUOTE 1) (SECOND X))) (T (SECOND X)))) ((= L 2) (IF (EQ OP (CAR X)) X (CONS OP (CDR X)))) (T (CONS OP (CONS (POST-OPTIMIZE (CONS OP (BUTLAST (CDR X)))) (LAST X))))))) (DEFUN ARITH-OPT (FORM &AUX NUM) ;;; 8/1/84 DNG - from MIT patch 98.40, add recognition of CLI:/. (IF (<= (LENGTH FORM) 2) FORM ;Let ARITHEXP handle this. (LOOP FOR ARG IN (CDR FORM) WHEN (SETQ NUM (QUOTE-NUMBER ARG)) COLLECT NUM INTO WINNERS ELSE COLLECT ARG INTO LOSERS FINALLY (RETURN (COND ((NULL (CDR WINNERS)) FORM) ;Can't hope to optimize. ((NULL LOSERS) (FOLD-CONSTANTS FORM)) ;Easy optimization. ;; Now we are left with at least two args which are numbers, but at ;; least one which is not. Frobbing with divide from here on is ;; dangerous, eg, (/ 5 a 4) must not optimize into (/ 1 a). ((MEMBER (CAR FORM) '(GLOBAL:/ QUOTIENT CLI:/ ) :TEST #'EQ) FORM) ;; The only special case left is DIFFERENCE, which treats ;; its first arg differently. ((OR (NOT (MEMBER (CAR FORM) '(- DIFFERENCE) :TEST #'EQ)) (QUOTE-NUMBER (CADR FORM))) `(,(CAR FORM) ',(APPLY (CAR FORM) WINNERS) . ,LOSERS)) (T `(,(CAR FORM) ,@LOSERS ',(APPLY #'+ WINNERS)))))))) ;;;; ================================== ;;;; Constant folding ;;;; ================================== ;; Arithmetic (ADD-POST-OPTIMIZER MINUS FOLD-ONE-ARG) (ADD-POST-OPTIMIZER 1+ FOLD-ONE-ARG) (ADD-POST-OPTIMIZER 1- FOLD-ONE-ARG) (ADD-POST-OPTIMIZER FLOOR ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER CEILING ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER TRUNCATE ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER ROUND ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER MOD ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER CLI:REM ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER %DIV ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER REMAINDER ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER GCD ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER LCM ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER ABS FOLD-ONE-ARG) ;; Logical (ADD-POST-OPTIMIZER ASH ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER LSH ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER ROT ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER DPB ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER LDB ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER SIGNED-LDB ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER %LOGDPB ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER %LOGLDB ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER LOGEQV ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER MASK-FIELD ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER BYTE ARITH-OPT-NON-ASSOCIATIVE) ;; Roots, powers, and logarithms (ADD-POST-OPTIMIZER SQRT FOLD-ONE-ARG) (ADD-POST-OPTIMIZER ISQRT FOLD-ONE-ARG) (ADD-POST-OPTIMIZER EXP FOLD-ONE-ARG) (ADD-POST-OPTIMIZER ^ ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER EXPT ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER LOG ARITH-OPT-NON-ASSOCIATIVE) ;; Trigonometry (ADD-POST-OPTIMIZER SIN FOLD-ONE-ARG) (ADD-POST-OPTIMIZER SIND FOLD-ONE-ARG) (ADD-POST-OPTIMIZER COS FOLD-ONE-ARG) (ADD-POST-OPTIMIZER COSD FOLD-ONE-ARG) (ADD-POST-OPTIMIZER TAN FOLD-ONE-ARG) (ADD-POST-OPTIMIZER ASIN FOLD-ONE-ARG) (ADD-POST-OPTIMIZER ACOS FOLD-ONE-ARG) (ADD-POST-OPTIMIZER GLOBAL:ATAN ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER CLI:ATAN ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER ATAN2 ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER CIS FOLD-ONE-ARG) ;; Hyperbolic functions (ADD-POST-OPTIMIZER SINH FOLD-ONE-ARG) (ADD-POST-OPTIMIZER COSH FOLD-ONE-ARG) (ADD-POST-OPTIMIZER TANH FOLD-ONE-ARG) (ADD-POST-OPTIMIZER ASINH FOLD-ONE-ARG) (ADD-POST-OPTIMIZER ACOSH FOLD-ONE-ARG) (ADD-POST-OPTIMIZER ATANH FOLD-ONE-ARG) ;; Numeric comparison (ADD-POST-OPTIMIZER < FOLD-NUMBERS) (ADD-POST-OPTIMIZER > FOLD-NUMBERS) (ADD-POST-OPTIMIZER = FOLD-NUMBERS) ;; Type conversions on numbers (ADD-POST-OPTIMIZER INTERNAL-FLOAT FOLD-ONE-ARG) (ADD-POST-OPTIMIZER SMALL-FLOAT FOLD-ONE-ARG) (ADD-POST-OPTIMIZER DOUBLE-FLOAT FOLD-ONE-ARG) (ADD-POST-OPTIMIZER LONG-FLOAT FOLD-ONE-ARG) (WHEN (CONSTANTP 'TARGET-PROCESSOR) (ADD-POST-OPTIMIZER %DATA-TYPE FOLD-ONE-ARG)) (ADD-POST-OPTIMIZER COMPLEX ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER NUMERATOR FOLD-ONE-ARG) (ADD-POST-OPTIMIZER DENOMINATOR FOLD-ONE-ARG) (ADD-POST-OPTIMIZER PHASE FOLD-ONE-ARG) (ADD-POST-OPTIMIZER RATIONAL FOLD-ONE-ARG) (ADD-POST-OPTIMIZER RATIONALIZE FOLD-ONE-ARG) (ADD-POST-OPTIMIZER SIGNUM FOLD-ONE-ARG) (ADD-POST-OPTIMIZER SI:COERCE-TO-SMALL-FLOAT FOLD-ONE-ARG) (ADD-POST-OPTIMIZER SI:COERCE-TO-SINGLE-FLOAT FOLD-ONE-ARG) (ADD-POST-OPTIMIZER SI:COERCE-TO-DOUBLE-FLOAT FOLD-ONE-ARG) (ADD-POST-OPTIMIZER SI:COERCE-TO-FLOAT FOLD-ONE-ARG) ;; Predicates on numbers (ADD-POST-OPTIMIZER NUMBERP (FOLD-TYPE-PREDICATE NUMBER)) (ADD-POST-OPTIMIZER ZEROP FOLD-NUMBERS) (ADD-POST-OPTIMIZER MINUSP FOLD-NUMBERS) (ADD-POST-OPTIMIZER PLUSP FOLD-NUMBERS) ; note: no post-optimizer for ODDP or EVENP because they are DEFSUBSTs (ADD-POST-OPTIMIZER FIXNUMP (FOLD-TYPE-PREDICATE #.(SI:TYPE-CANONICALIZE 'FIXNUM))) (ADD-POST-OPTIMIZER INTEGERP (FOLD-TYPE-PREDICATE INTEGER)) (ADD-POST-OPTIMIZER FIXP (FOLD-TYPE-PREDICATE INTEGER)) (ADD-POST-OPTIMIZER REALP (FOLD-TYPE-PREDICATE REAL)) (ADD-POST-OPTIMIZER FLOATP (FOLD-TYPE-PREDICATE FLOAT)) (ADD-POST-OPTIMIZER RATIONALP (FOLD-TYPE-PREDICATE RATIONAL)) (ADD-POST-OPTIMIZER RATIOP (FOLD-TYPE-PREDICATE RATIO)) (ADD-POST-OPTIMIZER CHARACTERP (FOLD-TYPE-PREDICATE CHARACTER)) (ADD-POST-OPTIMIZER COMPLEXP (FOLD-TYPE-PREDICATE COMPLEX)) (ADD-POST-OPTIMIZER SMALL-FLOATP (FOLD-TYPE-PREDICATE SHORT-FLOAT)) (ADD-POST-OPTIMIZER #.(GET 'SHORT-FLOAT 'SI:TYPE-PREDICATE) (FOLD-TYPE-PREDICATE SHORT-FLOAT)) (ADD-POST-OPTIMIZER #.(GET 'DOUBLE-FLOAT 'SI:TYPE-PREDICATE) (FOLD-TYPE-PREDICATE DOUBLE-FLOAT)) (ADD-POST-OPTIMIZER #.(GET 'LONG-FLOAT 'SI:TYPE-PREDICATE) (FOLD-TYPE-PREDICATE LONG-FLOAT)) ;; Character conversions (ADD-POST-OPTIMIZER CHAR-INT FOLD-ONE-ARG) (ADD-POST-OPTIMIZER INT-CHAR FOLD-ONE-ARG) (ADD-POST-OPTIMIZER CHAR-CODE FOLD-ONE-ARG) (ADD-POST-OPTIMIZER CHAR-BITS FOLD-ONE-ARG) (ADD-POST-OPTIMIZER CHAR-FONT FOLD-ONE-ARG) (ADD-POST-OPTIMIZER GLOBAL:CHARACTER FOLD-ONE-ARG) (ADD-POST-OPTIMIZER CLI:CHARACTER FOLD-ONE-ARG) (ADD-POST-OPTIMIZER CODE-CHAR ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER MAKE-CHAR ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER CHAR-NAME FOLD-ONE-ARG) (ADD-POST-OPTIMIZER NAME-CHAR FOLD-ONE-ARG) (ADD-POST-OPTIMIZER CHAR-DOWNCASE FOLD-ONE-ARG) (ADD-POST-OPTIMIZER CHAR-UPCASE FOLD-ONE-ARG) (ADD-POST-OPTIMIZER SI:COERCE-TO-CHARACTER FOLD-ONE-ARG) ;; Character predicates (ADD-POST-OPTIMIZER INTERNAL-CHAR-EQUAL ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER CHAR-LESSP ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER CHAR-GREATERP ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER CHAR-NOT-EQUAL ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER CHAR-NOT-GREATERP ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER CHAR-NOT-LESSP ARITH-OPT-NON-ASSOCIATIVE) (ADD-POST-OPTIMIZER ALPHA-CHAR-P FOLD-ONE-ARG) (ADD-POST-OPTIMIZER DIGIT-CHAR-P FOLD-ONE-ARG) (ADD-POST-OPTIMIZER STANDARD-CHAR-P FOLD-ONE-ARG) (ADD-POST-OPTIMIZER GRAPHIC-CHAR-P FOLD-ONE-ARG) (ADD-POST-OPTIMIZER STRING-CHAR-P FOLD-ONE-ARG) (ADD-POST-OPTIMIZER SI:FAT-STRING-CHAR-P FOLD-ONE-ARG) (ADD-POST-OPTIMIZER LOWER-CASE-P FOLD-ONE-ARG) (ADD-POST-OPTIMIZER UPPER-CASE-P FOLD-ONE-ARG) (ADD-POST-OPTIMIZER BOTH-CASE-P FOLD-ONE-ARG) (ADD-POST-OPTIMIZER ALPHANUMERICP FOLD-ONE-ARG) (DEFUN FOLD-NUMBERS ( FORM ) ;; 3/4/85 - Original version. (IF (LOOP FOR ARG IN (CDR FORM) ALWAYS (AND (CONSP ARG) (EQ (FIRST ARG) 'QUOTE) (NUMBERP (SECOND ARG)) ) ) (FOLD-CONSTANTS FORM) FORM)) ;;;; ================================== ;;;; Arithmetic optimizations ;;;; ================================== (ADD-POST-OPTIMIZER + PUT-CONST-LAST) (ADD-POST-OPTIMIZER * PUT-CONST-LAST) (ADD-POST-OPTIMIZER LOGAND PUT-CONST-LAST) (ADD-POST-OPTIMIZER LOGIOR PUT-CONST-LAST) (ADD-POST-OPTIMIZER LOGXOR PUT-CONST-LAST) (ADD-POST-OPTIMIZER = PUT-CONST-LAST) ;; For commutative operators, if one argument is a constant and the other is not, ;; make the constant the second argument so that the optimization routines for the ;; individual operators don't have to check for a constant in either of two places. ;; Also, if the first argument is a variable and the second is an expression, ;; then interchange them to save a MOVE instruction by making more efficient use ;; of the stack. (DEFUN PUT-CONST-LAST ( FORM ) ;; 7/25/85 - Use ADRREFP instead of TRIVIAL-FORM-P because non-local ;; lexical variables are not directly addressable. ;; 8/14/86 - Make sure to not optimize when more than two arguments. (COND ((QUOTEP (THIRD FORM)) FORM) ((NOT (ADRREFP (SECOND FORM))) FORM) ((NTHCDR 3 FORM) FORM) ((OR (QUOTEP (SECOND FORM)) (AND (NOT (ADRREFP (THIRD FORM))) (NO-SIDE-EFFECTS-P (THIRD FORM)) )) (LIST (FIRST FORM) (THIRD FORM) (SECOND FORM)) ) ( T FORM ) ) ) #| (ADD-POST-OPTIMIZER - REVERSE-SUBTRACTION) (DEFUN REVERSE-SUBTRACTION ( FORM ) ;; 7/26/85 - Original. (IF (AND (INSTRUCTION-EXISTS-P 'REVERSE-SUBTRACT) (NOT (ADRREFP (THIRD FORM))) (ADRREFP (SECOND FORM)) (NO-SIDE-EFFECTS-P (THIRD FORM)) ) (LIST 'REVERSE-SUBTRACT (THIRD FORM) (SECOND FORM)) FORM) ) |# (ADD-POST-OPTIMIZER * *TIMES-OPT) (ADD-POST-OPTIMIZER QUOTIENT *TIMES-OPT) (ADD-POST-OPTIMIZER %DIV *TIMES-OPT) (ADD-POST-OPTIMIZER GLOBAL:/ *TIMES-OPT) (ADD-POST-OPTIMIZER CLI:/ *TIMES-OPT) (DEFUN *TIMES-OPT ( FORM ) ;; 2/5/85 - use INC-VAR-USE. ;; 4/12/85 - Check SAFETY for * 1 [bug 1185] and don't optimize ;; unless constant is an integer [bug 1223]. ;; 7/25/85 - Use ADRREFP instead of TRIVIAL-FORM-P. ;;11/25/85 - Inhibit (* x 0) ==> 0 except in an inline expansion. ;; 5/08/86 - Use type checking for multiply by 0. ;; 8/14/86 - Changed *PLUS to + etc. (LET ((ARG2 (QUOTE-NUMBER (THIRD FORM)))) (COND ( (NULL ARG2) FORM ) ( (NOT (FIXNUMP ARG2)) ;; Can't optimize because it might prevent a type conversion. FORM ) ( (AND (= ARG2 1) ; (* x 1) ==> x (<= (OPT-SAFETY OPTIMIZE-SWITCH) (OPT-SPEED-OR-SPACE OPTIMIZE-SWITCH)) ) (SECOND FORM) ) ( (NEQ (FIRST FORM) '*) FORM ) ( (AND (= ARG2 0) ; (* x 0) ==> 0 ;; Check SAFETY because this optimization could ;; hide an error. (<= (OPT-SAFETY OPTIMIZE-SWITCH) (OPT-SPEED-OR-SPACE OPTIMIZE-SWITCH)) ;; Strictly speaking, this optimization is valid ;; only if x is known to be an integer. (OR (EXPR-TYPE-P (SECOND FORM) 'INTEGER) (EQ P1VALUE 'INTEGER))) (CONS 'PROGN (REST FORM)) ) ( (= ARG2 2) ; (* x 2) ==> (+ x x) (COND ((COMPILING-FOR-EXPLORER-P) `(+ (%DUP ,(SECOND FORM)) (%POP)) ) ((ADRREFP (SECOND FORM)) (LIST '+ (SECOND FORM) (INC-VAR-USE (SECOND FORM))) ) (T FORM) ) ) ( T FORM ) ))) (ADD-POST-OPTIMIZER LOGAND ARGS-SAME) (ADD-POST-OPTIMIZER LOGIOR ARGS-SAME) (ADD-POST-OPTIMIZER LOGXOR ARGS-SAME) (DEFUN ARGS-SAME ( FORM ) ;; 12/27/84 DNG - Original version written. ;; 2/06/85 DNG - Call DISCARD. ;; 4/12/85 DNG - Use EQUAL-FORMS instead of EQUAL. ;; 4/23/85 DNG - Check SAFETY. (IF (AND (EQUAL-FORMS (SECOND FORM) (THIRD FORM)) (NO-SIDE-EFFECTS-P (SECOND FORM)) (<= (OPT-SAFETY OPTIMIZE-SWITCH) (OPT-SPEED-OR-SPACE OPTIMIZE-SWITCH))) (PROGN (DISCARD (THIRD FORM)) (IF (EQ (FIRST FORM) 'LOGXOR) (PROGN (DISCARD (SECOND FORM)) '(QUOTE 0)) ; (LOGXOR x x) ==> 0 (SECOND FORM))) ; (LOGIOR x x) ==> x FORM) ) (ADD-POST-OPTIMIZER LOGAND LOGAND-OPT) (DEFUN LOGAND-OPT ( FORM ) ;; 12/27/84 DNG - Original version written. ;; 4/23/85 DNG - Check SAFETY. (LET ((ARG2 (QUOTE-NUMBER (THIRD FORM)))) (COND ( (NULL ARG2) FORM ) ( (> (OPT-SAFETY OPTIMIZE-SWITCH) (OPT-SPEED-OR-SPACE OPTIMIZE-SWITCH)) ;; If SAFETY is most important, don't risk hiding an argument type error. FORM) ( (= ARG2 -1) (SECOND FORM) ) ; (LOGAND x -1) ==> x ( (= ARG2 0) ; (LOGAND x 0) ==> 0 (CONS 'PROGN (REST FORM)) ) ( T FORM ) ))) (ADD-POST-OPTIMIZER + ADD-1-OPT) (ADD-POST-OPTIMIZER - ADD-1-OPT) (ADD-POST-OPTIMIZER LOGIOR ADD-1-OPT) (ADD-POST-OPTIMIZER LOGXOR ADD-1-OPT) (DEFUN ADD-1-OPT ( FORM ) ;; 4/12/85 DNG - Don't optimize out floating point 0 since ;; it might be forcing a type conversion. [bug 1223] ;; 4/23/85 DNG - Check SAFETY. [bug 1185] ;; 7/26/85 DNG - Avoid adding or subtracting negative constants. ;; 8/14/86 DNG - Changed *PLUS to + etc. (LET (( ARG2 (THIRD FORM) ) NUM2 ) (COND ((AND (EQ (FIRST FORM) '-) (EQUAL (SECOND FORM) '(QUOTE 0))) ; (- 0 x) ==> (MINUS x) (DISCARD (SECOND FORM)) `(MINUS ,ARG2) ) ((OR (NOT (QUOTEP ARG2)) (NOT (FIXNUMP (SETQ NUM2 (SECOND ARG2))))) FORM) ((AND (EQL NUM2 0) ; (+ x 0) ==> x (<= (OPT-SAFETY OPTIMIZE-SWITCH) (OPT-SPEED-OR-SPACE OPTIMIZE-SWITCH))) (DISCARD ARG2) (SECOND FORM) ) ((NOT (MEMBER (FIRST FORM) '(+ -) :TEST #'EQ)) FORM) ((EQL NUM2 1) ; (+ x 1) ==> (1+ x) (IF (EQ (FIRST FORM) '+) `(1+ ,(SECOND FORM)) `(1- ,(SECOND FORM)) )) ((< NUM2 0) ; (+ x -n) ==> (- x n) (LIST (IF (EQ (FIRST FORM) '+) '- '+) (SECOND FORM) `(QUOTE ,(- NUM2)))) (T FORM ) ))) (ADD-POST-OPTIMIZER ^ EXPT-OPT) (ADD-POST-OPTIMIZER EXPT EXPT-OPT) (DEFUN EXPT-OPT ( FORM ) ; (^ x 2) ==> (* x x) ;; 2/05/85 - Use INC-VAR-USE. ;; 7/25/85 - Use ADRREFP instead of TRIVIAL-FORM-P. ;; 8/14/86 - Changed *TIMES to *. (LET ((ARG2 (QUOTE-NUMBER (THIRD FORM)))) (COND ((OR (NULL ARG2) (NOT (= ARG2 2))) FORM) ((COMPILING-FOR-EXPLORER-P) `(* (%DUP ,(SECOND FORM)) (%POP)) ) ((ADRREFP (SECOND FORM)) `(* ,(SECOND FORM) ,( INC-VAR-USE (SECOND FORM))) ) (T FORM) ) ) ) (ADD-OPTIMIZER BOOLE BOOLE-EXPAND) (DEFUN BOOLE-EXPAND (X) ;; 9/27/86 DNG - Simplified; moved special cases of op to DEFINE-PATTERNS. (CASE (LENGTH (CDR X)) (2 (CADDR X)) (3 (CONS '*BOOLE (CDR X))) (T (LIST '*BOOLE (CADR X) (CONS 'BOOLE (BUTLAST (CDR X))) (CAR (LAST X)))))) (ADD-OPTIMIZER \\\\ CONVERT-GCD GCD) (ADD-OPTIMIZER GCD CONVERT-GCD) (DEFUN CONVERT-GCD (FORM) ;; 8/16/86 - Eliminated use of INTERNAL-\\\\. (IF (AND (EQ (FIRST FORM) 'GCD) (NULL (CDDDR FORM))) FORM (LOOP FOR ARG-FORM IN (CDDDR FORM) WITH ANSWER = `(GCD ,(SECOND FORM) ,(THIRD FORM)) DO (SETQ ANSWER `(GCD ,ANSWER ,ARG-FORM)) FINALLY (RETURN ANSWER)))) (ADD-POST-OPTIMIZER GLOBAL:FLOAT FLOAT-OPTIMIZER INTERNAL-FLOAT) (ADD-POST-OPTIMIZER CLI:FLOAT FLOAT-OPTIMIZER) (DEFUN FLOAT-OPTIMIZER (FORM &AUX NUM) ;; 11/12/85 DNG - Updated to handle CLI:FLOAT. ;; 1/15/87 DNG - Fix to handle double precision. (COND ((NULL (CDR FORM)) FORM) ; No arguments ((NULL (CDDR FORM)) ;One arg (IF (OR (EQ (FIRST FORM) 'GLOBAL:FLOAT) (EXPR-TYPE-P (SECOND FORM) 'INTEGER)) `(INTERNAL-FLOAT ,(SECOND FORM)) ; convert to single-precision floating point (FOLD-ONE-ARG FORM) ) ) ((AND (NULL (CDDDR FORM)) (SETQ NUM (QUOTE-NUMBER (THIRD FORM)))) ;Second arg a number (LIST (TYPECASE NUM (SHORT-FLOAT 'SMALL-FLOAT) #-IEEE-FLOATING-POINT (SINGLE-FLOAT 'INTERNAL-FLOAT) (DOUBLE-FLOAT 'DOUBLE-FLOAT) (LONG-FLOAT 'LONG-FLOAT) (T 'INTERNAL-FLOAT)) ; single precision (SECOND FORM))) (T FORM))) (ADD-POST-OPTIMIZER %MAKE-POINTER %MAKE-POINTER-OPT) (DEFUN %MAKE-POINTER-OPT ( FORM ) ;; This optimizer is needed for function ;; INT-CHAR which is a DEFSUBST that expands to: ;; (%MAKE-POINTER DTP-CHARACTER INTEGER) ;; 8/29/84 DNG - Original version. ;; 8/14/86 DNG - Watch out for cross-compilation where data type codes are different. (IF (AND (QUOTEP (THIRD FORM)) (MEMBER (QUOTE-NUMBER (SECOND FORM)) ; new data type '(#.DTP-FIX #.DTP-CHARACTER) :TEST #'EQ) (MEMBER (%DATA-TYPE (SECOND (THIRD FORM))) ; old data type '(#.DTP-FIX #.DTP-CHARACTER) :TEST #'EQ) #-Elroy (NOT (COMPILING-FOR-V2)) #+ELROY (COMPILING-FOR-V2) ) ;; Converting between integer and character constants (FOLD-CONSTANTS FORM) FORM )) ;;;; ================================== ;;;; Expand the numerical equality/sign predicates. ;;;; ================================== (ADD-POST-OPTIMIZER = =-OPTIMIZER) (DEFUN =-OPTIMIZER (FORM) ;; 2/5/85 - Use INC-VAR-USE. ;;8/14/86 - Merged function INTERNAL-=-OPTIMIZER into this one. (LET* ((ARGS (CDR FORM)) (N-ARGS (LENGTH ARGS))) (COND ((< N-ARGS 2) (WARN 'WRONG-NUMBER-OF-ARGUMENTS ':IMPLAUSIBLE "Too few arguments to ~S." (CAR FORM)) `(progn ,(car args) 't)) ((= N-ARGS 2) (COND ((QUOTE-ZERO-P (THIRD FORM)) ; (= x 0) ==> (zerop x) `(ZEROP ,(SECOND FORM)) ) ;; Note: (= 0 x) is handled by PUT-CONST-LAST ((DISCARD-EQUAL-FORMS FORM) ; (= x x) ==> T '(QUOTE T)) ((EQ (CAR FORM) '=) FORM) (T (CONS '= (CDR FORM))))) ((EVERY #'TRIVIAL-FORM-P (THE LIST (CDR ARGS))) (CONS 'AND (LOOP FOR ARG IN (CDR ARGS) AND FOR LAST-ARG FIRST (CAR ARGS) THEN (INC-VAR-USE ARG) COLLECT (POST-OPTIMIZE (LIST '= LAST-ARG ARG))))) (T FORM)))) (ADD-POST-OPTIMIZER CHAR-EQUAL CHAR-EQUAL-OPTIMIZER) (DEFUN CHAR-EQUAL-OPTIMIZER (FORM) ;; 2/5/85 - Use INC-VAR-USE. (LET* ((ARGS (CDR FORM)) (N-ARGS (LENGTH ARGS))) (COND ((< N-ARGS 2) `(progn ,(car args) 't)) ((= N-ARGS 2) `(INTERNAL-CHAR-EQUAL . ,ARGS)) ((EVERY #'TRIVIAL-FORM-P (THE LIST (CDR ARGS))) (CONS 'AND (LOOP FOR ARG IN (CDR ARGS) AND FOR LAST-ARG FIRST (CAR ARGS) THEN (INC-VAR-USE ARG) COLLECT (POST-OPTIMIZE (LIST 'INTERNAL-CHAR-EQUAL LAST-ARG ARG))))) (T FORM)))) (ADD-POST-OPTIMIZER > GREATERP-OPTIMIZER) (ADD-POST-OPTIMIZER GREATERP GREATERP-OPTIMIZER) (DEFUN GREATERP-OPTIMIZER (FORM) ;; 2/5/85 - Use INC-VAR-USE. ;; 6/25/85 - Use COMPARE-THREE to optimize 3 arbitrary arguments. ;; 8/14/86 - Merged INTERNAL->-OPTIMIZER into this one. ;; 9/11/86 - Make sure the second arg for LENGTH-GREATERP is a fixnum. (LET* ((ARGS (CDR FORM)) (N-ARGS (LENGTH ARGS))) (COND ((< N-ARGS 2) `(progn ,(car args) 't)) ((= N-ARGS 2) (COND ( (AND (CONSP (SECOND FORM)) (EQ (FIRST (SECOND FORM)) 'LENGTH) (COMPILING-FOR-EXPLORER-P) (EXPR-TYPE-P (THIRD FORM) 'FIXNUM)) `(LENGTH-GREATERP ,(SECOND (SECOND FORM)) ,(THIRD FORM)) ) ( (QUOTE-ZERO-P (THIRD FORM)) `(PLUSP ,(SECOND FORM)) ) ( (QUOTE-ZERO-P (SECOND FORM)) `(MINUSP ,(THIRD FORM)) ) ( (DISCARD-EQUAL-FORMS FORM) ; (> x x) ==> NIL '(QUOTE NIL)) ( (EQ (CAR FORM) '>) FORM) (T (CONS '> (CDR FORM))))) ((EVERY #'TRIVIAL-FORM-P (THE LIST (CDR ARGS))) (CONS 'AND (LOOP FOR ARG IN (CDR ARGS) AND FOR LAST-ARG FIRST (CAR ARGS) THEN (INC-VAR-USE ARG) COLLECT (POST-OPTIMIZE (LIST '> LAST-ARG ARG))))) ((AND (= N-ARGS 3) (>= (OPT-SPEED OPTIMIZE-SWITCH) (OPT-SPACE OPTIMIZE-SWITCH))) (COMPARE-THREE '> ARGS)) (T FORM)))) (ADD-POST-OPTIMIZER < LESSP-OPTIMIZER) (ADD-POST-OPTIMIZER LESSP LESSP-OPTIMIZER) (DEFUN LESSP-OPTIMIZER (FORM) ;; 2/5/85 - Use INC-VAR-USE. ;; 6/25/85 - Use COMPARE-THREE to optimize 3 arbitrary arguments. ;; 8/14/86 - Merged INTERNAL-<-OPTIMIZER with this one. ;; 9/11/86 - Make sure the second arg for LENGTH-GREATERP is a fixnum. (LET* ((ARGS (CDR FORM)) (N-ARGS (LENGTH ARGS))) (COND ((< N-ARGS 2) `(progn ,(car args) 't)) ((= N-ARGS 2) (LET ( NUM ) (COND ( (QUOTE-ZERO-P (THIRD FORM)) ; (< x 0) ==> (MINUSP x) `(MINUSP ,(SECOND FORM)) ) ( (QUOTEP (SECOND FORM)) ; (< c x) ==> (> x c) `(> ,(THIRD FORM) ,(SECOND FORM)) ) ( (AND (CONSP (SECOND FORM)) (EQ (FIRST (SECOND FORM)) 'LENGTH) (COMPILING-FOR-EXPLORER-P) (NOT (NULL (SETQ NUM (QUOTE-NUMBER (THIRD FORM))))) (FIXNUMP NUM) ) `(NOT (LENGTH-GREATERP ,(SECOND (SECOND FORM)) (QUOTE ,(- NUM 1)))) ) ( (DISCARD-EQUAL-FORMS FORM) ; (< x x) ==> NIL '(QUOTE NIL)) ((EQ (CAR FORM) '<) FORM) (T (CONS '< (CDR FORM)))))) ((EVERY #'TRIVIAL-FORM-P (THE LIST (CDR ARGS))) (CONS 'AND (LOOP FOR ARG IN (CDR ARGS) AND FOR LAST-ARG FIRST (CAR ARGS) THEN (INC-VAR-USE ARG) COLLECT (POST-OPTIMIZE (LIST '< LAST-ARG ARG))))) ((AND (= N-ARGS 3) (>= (OPT-SPEED OPTIMIZE-SWITCH) (OPT-SPACE OPTIMIZE-SWITCH))) (COMPARE-THREE '< ARGS)) (T FORM)))) (DEFUN COMPARE-THREE ( OPERATOR ARGS ) ;; Optimize three-argument comparison, taking care to ;; evaluate the arguments in the correct order. ;; 6/25/85 - Original version. ;; 9/19/86 - Use MARK-P1-DONE instead of P1-ALREADY-DONE. (P1 (LET ( (TEMP (GENSYM)) ) `(LET ((,TEMP (UNDEFINED-VALUE))) (AND (,OPERATOR ,(MARK-P1-DONE (FIRST ARGS)) (SETQ ,TEMP ,(MARK-P1-DONE (SECOND ARGS)))) (,OPERATOR ,TEMP ,(MARK-P1-DONE (THIRD ARGS))) ))))) (ADD-POST-OPTIMIZER >= (<=-OR->=-OPT <)) (ADD-POST-OPTIMIZER  (<=-OR->=-OPT <)) (ADD-POST-OPTIMIZER <= (<=-OR->=-OPT >)) (ADD-POST-OPTIMIZER  (<=-OR->=-OPT >)) (DEFUN <=-OR->=-OPT (FORM OPPOSITE) ;; 10/02/86 DNG - Merged <=-OPTIMIZER and >=-OPTIMIZER to form this function. (LET* ((ARGS (CDR FORM)) (N-ARGS (LENGTH ARGS))) (COND ((< N-ARGS 2) `(progn ,(car args) 't)) ((= N-ARGS 2) (LIST 'NOT (POST-OPTIMIZE (LIST* OPPOSITE ARGS)))) ((EVERY #'TRIVIAL-FORM-P (THE LIST (CDR ARGS))) (CONS 'AND (LOOP FOR ARG IN (CDR ARGS) AND FOR LAST-ARG FIRST (CAR ARGS) THEN (INC-VAR-USE ARG) COLLECT (POST-OPTIMIZE (LIST 'NOT (POST-OPTIMIZE (LIST OPPOSITE LAST-ARG ARG))))))) ((AND (= N-ARGS 3) (>= (OPT-SPEED OPTIMIZE-SWITCH) (OPT-SPACE OPTIMIZE-SWITCH))) (COMPARE-THREE (FIRST FORM) ARGS)) (T FORM)))) (ADD-POST-OPTIMIZER  -OPTIMIZER) (ADD-POST-OPTIMIZER /= -OPTIMIZER) (ADD-POST-OPTIMIZER CHAR-NOT-EQUAL (-OPTIMIZER CHAR-EQUAL)) (DEFUN -OPTIMIZER (FORM &OPTIONAL (OPPOSITE '=)) ;; 9/27/86 DNG - Changed from pre- to post-optimizer. ;; 12/08/86 DNG - Modify for use with CHAR-NOT-EQUAL; optimize the OR form. (LET* ((ARGS (CDR FORM)) (N-ARGS (LENGTH ARGS))) (DECLARE (LIST ARGS) (FIXNUM N-ARGS)) (COND ((< N-ARGS 2) `(progn ,(car args) 't)) ((= N-ARGS 2) `(NOT ,(POST-OPTIMIZE `(,OPPOSITE . ,ARGS)))) ((AND (= N-ARGS 3) (EVERY #'TRIVIAL-FORM-P ARGS)) `(NOT ,(POST-OPTIMIZE `(OR ,(POST-OPTIMIZE `(,OPPOSITE ,(CAR ARGS) ,(CADR ARGS))) ,(POST-OPTIMIZE `(,OPPOSITE ,(INC-VAR-USE (CAR ARGS)) ,(CADDR ARGS))) ,(POST-OPTIMIZE `(,OPPOSITE ,(INC-VAR-USE (CADR ARGS)) ,(INC-VAR-USE (CADDR ARGS)))))))) (T FORM)))) (ADD-POST-OPTIMIZER CHAR< LESSP-OPTIMIZER) (ADD-POST-OPTIMIZER CHAR> GREATERP-OPTIMIZER) (ADD-POST-OPTIMIZER CHAR>= (<=-OR->=-OPT <)) (ADD-POST-OPTIMIZER CHAR<= (<=-OR->=-OPT >)) (ADD-POST-OPTIMIZER CHAR (<=-OR->=-OPT <)) (ADD-POST-OPTIMIZER CHAR (<=-OR->=-OPT >)) (DEFCOMPILER-SYNONYM CHAR= =) ; to over-ride inapropriate definition by DEFSUBST. (ADD-POST-OPTIMIZER CHAR= =-OPTIMIZER) ; this is how it should be done. (ADD-POST-OPTIMIZER CHAR -OPTIMIZER) (ADD-POST-OPTIMIZER CHAR/= -OPTIMIZER) ;;; The following optimization must be done before the other optimizations that ;;; assume there are only two arguments. (ADD-POST-OPTIMIZER + ARITHEXP) (ADD-POST-OPTIMIZER * ARITHEXP) (ADD-POST-OPTIMIZER - ARITHEXP) (ADD-POST-OPTIMIZER GLOBAL:/ ARITHEXP) (ADD-POST-OPTIMIZER CLI:/ ARITHEXP) (ADD-POST-OPTIMIZER QUOTIENT ARITHEXP) (ADD-POST-OPTIMIZER LOGAND ARITHEXP) (ADD-POST-OPTIMIZER LOGIOR ARITHEXP) (ADD-POST-OPTIMIZER LOGXOR ARITHEXP) (ADD-POST-OPTIMIZER MIN ARITHEXP) (ADD-POST-OPTIMIZER MAX ARITHEXP) (ADD-POST-OPTIMIZER %DIV ARITHEXP) ;Optimize forms such as (+ 3 2) and (+ 3 a 2). These must be loaded after ARITHEXP ;so that they get done first (ADD-POST-OPTIMIZER reverses the order) (ADD-POST-OPTIMIZER + ARITH-OPT) (ADD-POST-OPTIMIZER * ARITH-OPT) (ADD-POST-OPTIMIZER - ARITH-OPT) (ADD-POST-OPTIMIZER GLOBAL:/ ARITH-OPT) (ADD-POST-OPTIMIZER CLI:/ ARITH-OPT) (ADD-POST-OPTIMIZER LOGIOR ARITH-OPT) (ADD-POST-OPTIMIZER LOGAND ARITH-OPT) (ADD-POST-OPTIMIZER LOGXOR ARITH-OPT) (ADD-POST-OPTIMIZER LOGEQV ARITH-OPT) (ADD-POST-OPTIMIZER MIN ARITH-OPT) (ADD-POST-OPTIMIZER MAX ARITH-OPT) (ADD-POST-OPTIMIZER QUOTIENT ARITH-OPT)