diff options
| -rw-r--r-- | lisp/emacs-lisp/cl-preloaded.el | 3 | ||||
| -rw-r--r-- | lisp/emacs-lisp/comp.el | 350 | ||||
| -rw-r--r-- | src/comp.c | 24 | ||||
| -rw-r--r-- | test/src/comp-tests.el | 82 |
4 files changed, 347 insertions, 112 deletions
diff --git a/lisp/emacs-lisp/cl-preloaded.el b/lisp/emacs-lisp/cl-preloaded.el index b5dbcbda473..eed43c5ed38 100644 --- a/lisp/emacs-lisp/cl-preloaded.el +++ b/lisp/emacs-lisp/cl-preloaded.el | |||
| @@ -52,8 +52,7 @@ | |||
| 52 | 52 | ||
| 53 | (defconst cl--typeof-types | 53 | (defconst cl--typeof-types |
| 54 | ;; Hand made from the source code of `type-of'. | 54 | ;; Hand made from the source code of `type-of'. |
| 55 | '((fixnum integer number number-or-marker atom) | 55 | '((integer number number-or-marker atom) |
| 56 | (bignum integer number number-or-marker atom) | ||
| 57 | (symbol atom) (string array sequence atom) | 56 | (symbol atom) (string array sequence atom) |
| 58 | (cons list sequence) | 57 | (cons list sequence) |
| 59 | ;; Markers aren't `numberp', yet they are accepted wherever integers are | 58 | ;; Markers aren't `numberp', yet they are accepted wherever integers are |
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el index 8bee8afeacf..ad0ac21389e 100644 --- a/lisp/emacs-lisp/comp.el +++ b/lisp/emacs-lisp/comp.el | |||
| @@ -191,19 +191,31 @@ For internal use only by the testsuite.") | |||
| 191 | Each function in FUNCTIONS is run after PASS. | 191 | Each function in FUNCTIONS is run after PASS. |
| 192 | Useful to hook into pass checkers.") | 192 | Useful to hook into pass checkers.") |
| 193 | 193 | ||
| 194 | (defconst comp-known-ret-types '((cons . cons) | 194 | (defconst comp-known-ret-types '((cons . (cons)) |
| 195 | (1+ . number) | 195 | (1+ . (number)) |
| 196 | (1- . number) | 196 | (1- . (number)) |
| 197 | (+ . number) | 197 | (+ . (number)) |
| 198 | (- . number) | 198 | (- . (number)) |
| 199 | (* . number) | 199 | (* . (number)) |
| 200 | (/ . number) | 200 | (/ . (number)) |
| 201 | (% . number) | 201 | (% . (number)) |
| 202 | ;; Type hints | 202 | ;; Type hints |
| 203 | (comp-hint-fixnum . fixnum) | 203 | (comp-hint-cons . (cons))) |
| 204 | (comp-hint-cons . cons)) | ||
| 205 | "Alist used for type propagation.") | 204 | "Alist used for type propagation.") |
| 206 | 205 | ||
| 206 | (defconst comp-known-ret-ranges | ||
| 207 | `((comp-hint-fixnum . (,most-negative-fixnum . ,most-positive-fixnum))) | ||
| 208 | "Known returned ranges.") | ||
| 209 | |||
| 210 | ;; TODO fill it. | ||
| 211 | (defconst comp-type-predicates '((cons . consp) | ||
| 212 | (float . floatp) | ||
| 213 | (integer . integerp) | ||
| 214 | (number . numberp) | ||
| 215 | (string . stringp) | ||
| 216 | (symbol . symbolp)) | ||
| 217 | "Alist type -> predicate.") | ||
| 218 | |||
| 207 | (defconst comp-symbol-values-optimizable '(most-positive-fixnum | 219 | (defconst comp-symbol-values-optimizable '(most-positive-fixnum |
| 208 | most-negative-fixnum) | 220 | most-negative-fixnum) |
| 209 | "Symbol values we can resolve in the compile-time.") | 221 | "Symbol values we can resolve in the compile-time.") |
| @@ -285,9 +297,9 @@ This is tipically for top-level forms other than defun.") | |||
| 285 | :documentation "Relocated data not necessary after load.") | 297 | :documentation "Relocated data not necessary after load.") |
| 286 | (with-late-load nil :type boolean | 298 | (with-late-load nil :type boolean |
| 287 | :documentation "When non-nil support late load.") | 299 | :documentation "When non-nil support late load.") |
| 288 | (supertype-memoize (make-hash-table :test #'equal) :type hash-table | 300 | (union-typesets-mem (make-hash-table :test #'equal) :type hash-table |
| 289 | :documentation "Serve memoization for | 301 | :documentation "Serve memoization for |
| 290 | `comp-common-supertype'.")) | 302 | `comp-union-typesets'.")) |
| 291 | 303 | ||
| 292 | (cl-defstruct comp-args-base | 304 | (cl-defstruct comp-args-base |
| 293 | (min nil :type number | 305 | (min nil :type number |
| @@ -419,14 +431,68 @@ CFG is mutated by a pass.") | |||
| 419 | (slot nil :type (or fixnum symbol) | 431 | (slot nil :type (or fixnum symbol) |
| 420 | :documentation "Slot number in the array if a number or | 432 | :documentation "Slot number in the array if a number or |
| 421 | 'scratch' for scratch slot.") | 433 | 'scratch' for scratch slot.") |
| 422 | (const-vld nil :type boolean | 434 | (typeset '(t) :type list |
| 423 | :documentation "Valid signal for the following slot.") | 435 | :documentation "List of possible types the mvar can assume. |
| 424 | (constant nil | 436 | Each element cannot be a subtype of any other element of this slot.") |
| 425 | :documentation "When const-vld non-nil this is used for holding | 437 | (valset '() :type list |
| 426 | a value known at compile time.") | 438 | :documentation "List of possible values the mvar can assume. |
| 427 | (type nil :type symbol | 439 | Interg values are handled in the `range' slot.") |
| 428 | :documentation "When non-nil indicates the type when known at compile | 440 | (range '() :type list |
| 429 | time.")) | 441 | :documentation "Integer interval.")) |
| 442 | |||
| 443 | (defsubst comp-mvar-value-vld-p (mvar) | ||
| 444 | "Return t if one single value can be extracted by the MVAR constrains." | ||
| 445 | (or (= (length (comp-mvar-valset mvar)) 1) | ||
| 446 | (let ((r (comp-mvar-range mvar))) | ||
| 447 | (and (= (length r) 1) | ||
| 448 | (let ((low (caar r)) | ||
| 449 | (high (cdar r))) | ||
| 450 | (and | ||
| 451 | (integerp low) | ||
| 452 | (integerp high) | ||
| 453 | (= low high))))))) | ||
| 454 | |||
| 455 | (defsubst comp-mvar-value (mvar) | ||
| 456 | "Return the constant value of MVAR. | ||
| 457 | `comp-mvar-value-vld-p' *must* be satisfied before calling | ||
| 458 | `comp-mvar-const'." | ||
| 459 | (declare (gv-setter | ||
| 460 | (lambda (val) | ||
| 461 | `(if (integerp ,val) | ||
| 462 | (setf (comp-mvar-typeset ,mvar) nil | ||
| 463 | (comp-mvar-range ,mvar) (list (cons ,val ,val))) | ||
| 464 | (setf (comp-mvar-typeset ,mvar) nil | ||
| 465 | (comp-mvar-valset ,mvar) (list ,val)))))) | ||
| 466 | (let ((v (comp-mvar-valset mvar))) | ||
| 467 | (if (= (length v) 1) | ||
| 468 | (car v) | ||
| 469 | (caar (comp-mvar-range mvar))))) | ||
| 470 | |||
| 471 | (defsubst comp-mvar-fixnum-p (mvar) | ||
| 472 | "Return t if MVAR is certainly a fixnum." | ||
| 473 | (when-let (range (comp-mvar-range mvar)) | ||
| 474 | (let* ((low (caar range)) | ||
| 475 | (high (cdar (last range)))) | ||
| 476 | (unless (or (eq low '-) | ||
| 477 | (< low most-negative-fixnum) | ||
| 478 | (eq high '+) | ||
| 479 | (> high most-positive-fixnum)) | ||
| 480 | t)))) | ||
| 481 | |||
| 482 | (defsubst comp-mvar-symbol-p (mvar) | ||
| 483 | "Return t if MVAR is certainly a symbol." | ||
| 484 | (equal (comp-mvar-typeset mvar) '(symbol))) | ||
| 485 | |||
| 486 | (defsubst comp-mvar-cons-p (mvar) | ||
| 487 | "Return t if MVAR is certainly a cons." | ||
| 488 | (equal (comp-mvar-typeset mvar) '(cons))) | ||
| 489 | |||
| 490 | (defun comp-mvar-type-hint-match-p (mvar type-hint) | ||
| 491 | "Match MVAR against TYPE-HINT. | ||
| 492 | In use by the backend." | ||
| 493 | (cl-ecase type-hint | ||
| 494 | (cons (comp-mvar-cons-p mvar)) | ||
| 495 | (fixnum (comp-mvar-fixnum-p mvar)))) | ||
| 430 | 496 | ||
| 431 | ;; Special vars used by some passes | 497 | ;; Special vars used by some passes |
| 432 | (defvar comp-func) | 498 | (defvar comp-func) |
| @@ -463,6 +529,14 @@ To be used by all entry points." | |||
| 463 | "Type-hint predicate for function name FUNC." | 529 | "Type-hint predicate for function name FUNC." |
| 464 | (when (memq func comp-type-hints) t)) | 530 | (when (memq func comp-type-hints) t)) |
| 465 | 531 | ||
| 532 | (defsubst comp-func-ret-typeset (func) | ||
| 533 | "Return the typeset returned by function FUNC. " | ||
| 534 | (or (alist-get func comp-known-ret-types) '(t))) | ||
| 535 | |||
| 536 | (defsubst comp-func-ret-range (func) | ||
| 537 | "Return the range returned by function FUNC. " | ||
| 538 | (alist-get func comp-known-ret-ranges)) | ||
| 539 | |||
| 466 | (defun comp-func-unique-in-cu-p (func) | 540 | (defun comp-func-unique-in-cu-p (func) |
| 467 | "Return t if FUNC is known to be unique in the current compilation unit." | 541 | "Return t if FUNC is known to be unique in the current compilation unit." |
| 468 | (if (symbolp func) | 542 | (if (symbolp func) |
| @@ -943,10 +1017,14 @@ STACK-OFF is the index of the first slot frame involved." | |||
| 943 | collect (comp-slot-n sp)))) | 1017 | collect (comp-slot-n sp)))) |
| 944 | 1018 | ||
| 945 | (cl-defun make-comp-mvar (&key slot (constant nil const-vld) type) | 1019 | (cl-defun make-comp-mvar (&key slot (constant nil const-vld) type) |
| 946 | (when const-vld | 1020 | "`comp-mvar' intitializer." |
| 947 | (comp-add-const-to-relocs constant)) | 1021 | (let ((mvar (make--comp-mvar :slot slot))) |
| 948 | (make--comp-mvar :slot slot :const-vld const-vld :constant constant | 1022 | (when const-vld |
| 949 | :type type)) | 1023 | (comp-add-const-to-relocs constant) |
| 1024 | (setf (comp-mvar-value mvar) constant)) | ||
| 1025 | (when type | ||
| 1026 | (setf (comp-mvar-typeset mvar) (list type))) | ||
| 1027 | mvar)) | ||
| 950 | 1028 | ||
| 951 | (defun comp-new-frame (size &optional ssa) | 1029 | (defun comp-new-frame (size &optional ssa) |
| 952 | "Return a clean frame of meta variables of size SIZE. | 1030 | "Return a clean frame of meta variables of size SIZE. |
| @@ -1823,11 +1901,9 @@ blocks." | |||
| 1823 | ;; this form is called 'minimal SSA form'. | 1901 | ;; this form is called 'minimal SSA form'. |
| 1824 | ;; This pass should be run every time basic blocks or m-var are shuffled. | 1902 | ;; This pass should be run every time basic blocks or m-var are shuffled. |
| 1825 | 1903 | ||
| 1826 | (cl-defun make-comp-ssa-mvar (&key slot (constant nil const-vld) type) | 1904 | (cl-defun make-comp-ssa-mvar (&rest rest &key _slot _constant _type) |
| 1827 | (let ((mvar (make--comp-mvar :slot slot | 1905 | "Same as `make-comp-mvar' but set the `id' slot." |
| 1828 | :const-vld const-vld | 1906 | (let ((mvar (apply #'make-comp-mvar rest))) |
| 1829 | :constant constant | ||
| 1830 | :type type))) | ||
| 1831 | (setf (comp-mvar-id mvar) (sxhash-eq mvar)) | 1907 | (setf (comp-mvar-id mvar) (sxhash-eq mvar)) |
| 1832 | mvar)) | 1908 | mvar)) |
| 1833 | 1909 | ||
| @@ -2130,19 +2206,18 @@ PRE-LAMBDA and POST-LAMBDA are called in pre or post-order if non-nil." | |||
| 2130 | ;; This is also responsible for removing function calls to pure functions if | 2206 | ;; This is also responsible for removing function calls to pure functions if |
| 2131 | ;; possible. | 2207 | ;; possible. |
| 2132 | 2208 | ||
| 2133 | (defsubst comp-strict-type-of (obj) | 2209 | (defconst comp--typeof-types (mapcar (lambda (x) |
| 2134 | "Given OBJ return its type understanding fixnums." | 2210 | (append x '(t))) |
| 2135 | ;; Should be certainly smarter but now we take advantages just from fixnums. | 2211 | cl--typeof-types) |
| 2136 | (if (fixnump obj) | 2212 | ;; TODO can we just add t in `cl--typeof-types'? |
| 2137 | 'fixnum | 2213 | "Like `cl--typeof-types' but with t as common supertype.") |
| 2138 | (type-of obj))) | ||
| 2139 | 2214 | ||
| 2140 | (defun comp-supertypes (type) | 2215 | (defun comp-supertypes (type) |
| 2141 | "Return a list of pairs (supertype . hierarchy-level) for TYPE." | 2216 | "Return a list of pairs (supertype . hierarchy-level) for TYPE." |
| 2142 | (cl-loop | 2217 | (cl-loop |
| 2143 | named outer | 2218 | named outer |
| 2144 | with found = nil | 2219 | with found = nil |
| 2145 | for l in cl--typeof-types | 2220 | for l in comp--typeof-types |
| 2146 | do (cl-loop | 2221 | do (cl-loop |
| 2147 | for x in l | 2222 | for x in l |
| 2148 | for i from (length l) downto 0 | 2223 | for i from (length l) downto 0 |
| @@ -2165,10 +2240,105 @@ PRE-LAMBDA and POST-LAMBDA are called in pre or post-order if non-nil." | |||
| 2165 | 2240 | ||
| 2166 | (defun comp-common-supertype (&rest types) | 2241 | (defun comp-common-supertype (&rest types) |
| 2167 | "Return the first common supertype of TYPES." | 2242 | "Return the first common supertype of TYPES." |
| 2168 | (or (gethash types (comp-ctxt-supertype-memoize comp-ctxt)) | 2243 | (cl-reduce #'comp-common-supertype-2 types)) |
| 2169 | (puthash types | 2244 | |
| 2170 | (cl-reduce #'comp-common-supertype-2 types) | 2245 | (defsubst comp-subtype-p (type1 type2) |
| 2171 | (comp-ctxt-supertype-memoize comp-ctxt)))) | 2246 | "Return t if TYPE1 is a subtype of TYPE1 or nil otherwise." |
| 2247 | (eq (comp-common-supertype-2 type1 type2) type2)) | ||
| 2248 | |||
| 2249 | (defun comp-union-typesets (&rest typesets) | ||
| 2250 | "Union types present into TYPESETS." | ||
| 2251 | (or (gethash typesets (comp-ctxt-union-typesets-mem comp-ctxt)) | ||
| 2252 | (puthash typesets | ||
| 2253 | (cl-loop | ||
| 2254 | with types = (apply #'append typesets) | ||
| 2255 | with res = '() | ||
| 2256 | for lane in comp--typeof-types | ||
| 2257 | do (cl-loop | ||
| 2258 | with last = nil | ||
| 2259 | for x in lane | ||
| 2260 | when (memq x types) | ||
| 2261 | do (setf last x) | ||
| 2262 | finally (when last | ||
| 2263 | (push last res))) | ||
| 2264 | finally (cl-return (cl-remove-duplicates res))) | ||
| 2265 | (comp-ctxt-union-typesets-mem comp-ctxt)))) | ||
| 2266 | |||
| 2267 | (defsubst comp-range-1+ (x) | ||
| 2268 | (if (symbolp x) | ||
| 2269 | x | ||
| 2270 | (1+ x))) | ||
| 2271 | |||
| 2272 | (defsubst comp-range-1- (x) | ||
| 2273 | (if (symbolp x) | ||
| 2274 | x | ||
| 2275 | (1- x))) | ||
| 2276 | |||
| 2277 | (defsubst comp-range-< (x y) | ||
| 2278 | (cond | ||
| 2279 | ((eq x '+) nil) | ||
| 2280 | ((eq x '-) t) | ||
| 2281 | ((eq y '+) t) | ||
| 2282 | ((eq y '-) nil) | ||
| 2283 | (t (< x y)))) | ||
| 2284 | |||
| 2285 | (defun comp-range-union (&rest ranges) | ||
| 2286 | "Combine integer intervals RANGES by union operation." | ||
| 2287 | (cl-loop | ||
| 2288 | with all-ranges = (apply #'append ranges) | ||
| 2289 | with lows = (mapcar (lambda (x) | ||
| 2290 | (cons (comp-range-1- (car x)) 'l)) | ||
| 2291 | all-ranges) | ||
| 2292 | with highs = (mapcar (lambda (x) | ||
| 2293 | (cons (cdr x) 'h)) | ||
| 2294 | all-ranges) | ||
| 2295 | with nest = 0 | ||
| 2296 | with low = nil | ||
| 2297 | with res = () | ||
| 2298 | for (i . x) in (cl-sort (nconc lows highs) #'comp-range-< :key #'car) | ||
| 2299 | if (eq x 'l) | ||
| 2300 | do | ||
| 2301 | (when (zerop nest) | ||
| 2302 | (setf low i)) | ||
| 2303 | (cl-incf nest) | ||
| 2304 | else | ||
| 2305 | do | ||
| 2306 | (when (= nest 1) | ||
| 2307 | (push `(,(comp-range-1+ low) . ,i) res)) | ||
| 2308 | (cl-decf nest) | ||
| 2309 | finally (cl-return (reverse res)))) | ||
| 2310 | |||
| 2311 | (defun comp-range-intersection (&rest ranges) | ||
| 2312 | "Combine integer intervals RANGES by intersecting." | ||
| 2313 | (cl-loop | ||
| 2314 | with all-ranges = (apply #'append ranges) | ||
| 2315 | with n-ranges = (length ranges) | ||
| 2316 | with lows = (mapcar (lambda (x) | ||
| 2317 | (cons (car x) 'l)) | ||
| 2318 | all-ranges) | ||
| 2319 | with highs = (mapcar (lambda (x) | ||
| 2320 | (cons (cdr x) 'h)) | ||
| 2321 | all-ranges) | ||
| 2322 | with nest = 0 | ||
| 2323 | with low = nil | ||
| 2324 | with res = () | ||
| 2325 | initially (when (cl-some #'null ranges) | ||
| 2326 | ;; Intersecting with a null range always results in a | ||
| 2327 | ;; null range. | ||
| 2328 | (cl-return '())) | ||
| 2329 | for (i . x) in (cl-sort (nconc lows highs) #'comp-range-< :key #'car) | ||
| 2330 | if (eq x 'l) | ||
| 2331 | do | ||
| 2332 | (cl-incf nest) | ||
| 2333 | (when (= nest n-ranges) | ||
| 2334 | (setf low i)) | ||
| 2335 | else | ||
| 2336 | do | ||
| 2337 | (when (= nest n-ranges) | ||
| 2338 | (push `(,low . ,i) | ||
| 2339 | res)) | ||
| 2340 | (cl-decf nest) | ||
| 2341 | finally (cl-return (reverse res)))) | ||
| 2172 | 2342 | ||
| 2173 | (defun comp-copy-insn (insn) | 2343 | (defun comp-copy-insn (insn) |
| 2174 | "Deep copy INSN." | 2344 | "Deep copy INSN." |
| @@ -2213,20 +2383,18 @@ Forward propagate immediate involed in assignments." | |||
| 2213 | for insn in (comp-block-insns b) | 2383 | for insn in (comp-block-insns b) |
| 2214 | do (pcase insn | 2384 | do (pcase insn |
| 2215 | (`(setimm ,lval ,v) | 2385 | (`(setimm ,lval ,v) |
| 2216 | (setf (comp-mvar-const-vld lval) t | 2386 | (setf (comp-mvar-value lval) v)))))) |
| 2217 | (comp-mvar-constant lval) v | ||
| 2218 | (comp-mvar-type lval) (comp-strict-type-of v))))))) | ||
| 2219 | 2387 | ||
| 2220 | (defsubst comp-mvar-propagate (lval rval) | 2388 | (defsubst comp-mvar-propagate (lval rval) |
| 2221 | "Propagate into LVAL properties of RVAL." | 2389 | "Propagate into LVAL properties of RVAL." |
| 2222 | (setf (comp-mvar-const-vld lval) (comp-mvar-const-vld rval) | 2390 | (setf (comp-mvar-typeset lval) (comp-mvar-typeset rval) |
| 2223 | (comp-mvar-constant lval) (comp-mvar-constant rval) | 2391 | (comp-mvar-valset lval) (comp-mvar-valset rval) |
| 2224 | (comp-mvar-type lval) (comp-mvar-type rval))) | 2392 | (comp-mvar-range lval) (comp-mvar-range rval))) |
| 2225 | 2393 | ||
| 2226 | (defsubst comp-function-foldable-p (f args) | 2394 | (defsubst comp-function-foldable-p (f args) |
| 2227 | "Given function F called with ARGS return non-nil when optimizable." | 2395 | "Given function F called with ARGS return non-nil when optimizable." |
| 2228 | (and (cl-every #'comp-mvar-const-vld args) | 2396 | (and (comp-function-pure-p f) |
| 2229 | (comp-function-pure-p f))) | 2397 | (cl-every #'comp-mvar-value-vld-p args))) |
| 2230 | 2398 | ||
| 2231 | (defsubst comp-function-call-maybe-fold (insn f args) | 2399 | (defsubst comp-function-call-maybe-fold (insn f args) |
| 2232 | "Given INSN when F is pure if all ARGS are known remove the function call." | 2400 | "Given INSN when F is pure if all ARGS are known remove the function call." |
| @@ -2238,10 +2406,10 @@ Forward propagate immediate involed in assignments." | |||
| 2238 | (cond | 2406 | (cond |
| 2239 | ((eq f 'symbol-value) | 2407 | ((eq f 'symbol-value) |
| 2240 | (when-let* ((arg0 (car args)) | 2408 | (when-let* ((arg0 (car args)) |
| 2241 | (const (comp-mvar-const-vld arg0)) | 2409 | (const (comp-mvar-value-vld-p arg0)) |
| 2242 | (ok-to-optim (member (comp-mvar-constant arg0) | 2410 | (ok-to-optim (member (comp-mvar-value arg0) |
| 2243 | comp-symbol-values-optimizable))) | 2411 | comp-symbol-values-optimizable))) |
| 2244 | (rewrite-insn-as-setimm insn (symbol-value (comp-mvar-constant | 2412 | (rewrite-insn-as-setimm insn (symbol-value (comp-mvar-value |
| 2245 | (car args)))))) | 2413 | (car args)))))) |
| 2246 | ((comp-function-foldable-p f args) | 2414 | ((comp-function-foldable-p f args) |
| 2247 | (ignore-errors | 2415 | (ignore-errors |
| @@ -2254,7 +2422,7 @@ Forward propagate immediate involed in assignments." | |||
| 2254 | ;; and know to be pure. | 2422 | ;; and know to be pure. |
| 2255 | (comp-func-byte-func f-in-ctxt) | 2423 | (comp-func-byte-func f-in-ctxt) |
| 2256 | f)) | 2424 | f)) |
| 2257 | (value (comp-apply-in-env f (mapcar #'comp-mvar-constant args)))) | 2425 | (value (comp-apply-in-env f (mapcar #'comp-mvar-value args)))) |
| 2258 | (rewrite-insn-as-setimm insn value))))))) | 2426 | (rewrite-insn-as-setimm insn value))))))) |
| 2259 | 2427 | ||
| 2260 | (defun comp-fwprop-insn (insn) | 2428 | (defun comp-fwprop-insn (insn) |
| @@ -2263,13 +2431,19 @@ Forward propagate immediate involed in assignments." | |||
| 2263 | (`(set ,lval ,rval) | 2431 | (`(set ,lval ,rval) |
| 2264 | (pcase rval | 2432 | (pcase rval |
| 2265 | (`(,(or 'call 'callref) ,f . ,args) | 2433 | (`(,(or 'call 'callref) ,f . ,args) |
| 2266 | (setf (comp-mvar-type lval) | 2434 | (if-let ((range (comp-func-ret-range f))) |
| 2267 | (alist-get f comp-known-ret-types)) | 2435 | (setf (comp-mvar-range lval) (list range) |
| 2436 | (comp-mvar-typeset lval) nil) | ||
| 2437 | (setf (comp-mvar-typeset lval) | ||
| 2438 | (comp-func-ret-typeset f))) | ||
| 2268 | (comp-function-call-maybe-fold insn f args)) | 2439 | (comp-function-call-maybe-fold insn f args)) |
| 2269 | (`(,(or 'direct-call 'direct-callref) ,f . ,args) | 2440 | (`(,(or 'direct-call 'direct-callref) ,f . ,args) |
| 2270 | (let ((f (comp-func-name (gethash f (comp-ctxt-funcs-h comp-ctxt))))) | 2441 | (let ((f (comp-func-name (gethash f (comp-ctxt-funcs-h comp-ctxt))))) |
| 2271 | (setf (comp-mvar-type lval) | 2442 | (if-let ((range (comp-func-ret-range f))) |
| 2272 | (alist-get f comp-known-ret-types)) | 2443 | (setf (comp-mvar-range lval) (list range) |
| 2444 | (comp-mvar-typeset lval) nil) | ||
| 2445 | (setf (comp-mvar-typeset lval) | ||
| 2446 | (comp-func-ret-typeset f))) | ||
| 2273 | (comp-function-call-maybe-fold insn f args))) | 2447 | (comp-function-call-maybe-fold insn f args))) |
| 2274 | (_ | 2448 | (_ |
| 2275 | (comp-mvar-propagate lval rval)))) | 2449 | (comp-mvar-propagate lval rval)))) |
| @@ -2278,31 +2452,46 @@ Forward propagate immediate involed in assignments." | |||
| 2278 | ('eq | 2452 | ('eq |
| 2279 | (comp-mvar-propagate lval rval)) | 2453 | (comp-mvar-propagate lval rval)) |
| 2280 | ((or 'eql 'equal) | 2454 | ((or 'eql 'equal) |
| 2281 | (if (memq (comp-mvar-type rval) '(symbol fixnum)) | 2455 | (if (or (comp-mvar-symbol-p rval) |
| 2456 | (comp-mvar-fixnum-p rval)) | ||
| 2282 | (comp-mvar-propagate lval rval) | 2457 | (comp-mvar-propagate lval rval) |
| 2283 | (setf (comp-mvar-type lval) (comp-mvar-type rval)))) | 2458 | (setf (comp-mvar-typeset lval) (comp-mvar-typeset rval)))) |
| 2284 | ('= | 2459 | ('= |
| 2285 | (if (eq (comp-mvar-type rval) 'fixnum) | 2460 | (if (comp-mvar-fixnum-p rval) |
| 2286 | (comp-mvar-propagate lval rval) | 2461 | (comp-mvar-propagate lval rval) |
| 2287 | (setf (comp-mvar-type lval) 'number))))) | 2462 | (setf (comp-mvar-typeset lval) |
| 2463 | (unless (comp-mvar-range rval) | ||
| 2464 | '(number))))))) | ||
| 2288 | (`(setimm ,lval ,v) | 2465 | (`(setimm ,lval ,v) |
| 2289 | (setf (comp-mvar-const-vld lval) t | 2466 | (setf (comp-mvar-value lval) v)) |
| 2290 | (comp-mvar-constant lval) v | ||
| 2291 | (comp-mvar-type lval) (comp-strict-type-of v))) | ||
| 2292 | (`(phi ,lval . ,rest) | 2467 | (`(phi ,lval . ,rest) |
| 2293 | (let ((rvals (mapcar #'car rest))) | 2468 | (let* ((rvals (mapcar #'car rest)) |
| 2294 | ;; Forward const prop here. | 2469 | (values (mapcar #'comp-mvar-valset rvals)) |
| 2295 | (when-let* ((vld (cl-every #'comp-mvar-const-vld rvals)) | 2470 | (from-latch (cl-some |
| 2296 | (consts (mapcar #'comp-mvar-constant rvals)) | 2471 | (lambda (x) |
| 2297 | (x (car consts)) | 2472 | (comp-latch-p |
| 2298 | (equals (cl-every (lambda (y) (equal x y)) consts))) | 2473 | (gethash (cdr x) |
| 2299 | (setf (comp-mvar-const-vld lval) t | 2474 | (comp-func-blocks comp-func)))) |
| 2300 | (comp-mvar-constant lval) x)) | 2475 | rest))) |
| 2301 | ;; Forward type propagation. | 2476 | |
| 2302 | (when-let* ((types (mapcar #'comp-mvar-type rvals)) | 2477 | ;; Type propagation. |
| 2303 | (non-empty (cl-notany #'null types)) | 2478 | (setf (comp-mvar-typeset lval) |
| 2304 | (x (comp-common-supertype types))) | 2479 | (apply #'comp-union-typesets (mapcar #'comp-mvar-typeset rvals))) |
| 2305 | (setf (comp-mvar-type lval) x)))))) | 2480 | ;; Value propagation. |
| 2481 | (setf (comp-mvar-valset lval) | ||
| 2482 | (when (cl-every #'consp values) | ||
| 2483 | ;; TODO memoize? | ||
| 2484 | (cl-remove-duplicates (apply #'append values) | ||
| 2485 | :test #'equal))) | ||
| 2486 | ;; Range propagation | ||
| 2487 | (setf (comp-mvar-range lval) | ||
| 2488 | (when (and (not from-latch) | ||
| 2489 | (cl-notany (lambda (x) | ||
| 2490 | (comp-subtype-p 'integer x)) | ||
| 2491 | (comp-mvar-typeset lval))) | ||
| 2492 | ;; TODO memoize? | ||
| 2493 | (apply #'comp-range-union | ||
| 2494 | (mapcar #'comp-mvar-range rvals)))))))) | ||
| 2306 | 2495 | ||
| 2307 | (defun comp-fwprop* () | 2496 | (defun comp-fwprop* () |
| 2308 | "Propagate for set* and phi operands. | 2497 | "Propagate for set* and phi operands. |
| @@ -2416,11 +2605,11 @@ FUNCTION can be a function-name or byte compiled function." | |||
| 2416 | (pcase insn | 2605 | (pcase insn |
| 2417 | (`(set ,lval (callref funcall ,f . ,rest)) | 2606 | (`(set ,lval (callref funcall ,f . ,rest)) |
| 2418 | (when-let ((new-form (comp-call-optim-form-call | 2607 | (when-let ((new-form (comp-call-optim-form-call |
| 2419 | (comp-mvar-constant f) rest))) | 2608 | (comp-mvar-value f) rest))) |
| 2420 | (setf insn `(set ,lval ,new-form)))) | 2609 | (setf insn `(set ,lval ,new-form)))) |
| 2421 | (`(callref funcall ,f . ,rest) | 2610 | (`(callref funcall ,f . ,rest) |
| 2422 | (when-let ((new-form (comp-call-optim-form-call | 2611 | (when-let ((new-form (comp-call-optim-form-call |
| 2423 | (comp-mvar-constant f) rest))) | 2612 | (comp-mvar-value f) rest))) |
| 2424 | (setf insn new-form))))))) | 2613 | (setf insn new-form))))))) |
| 2425 | 2614 | ||
| 2426 | (defun comp-call-optim (_) | 2615 | (defun comp-call-optim (_) |
| @@ -2639,7 +2828,8 @@ Update all insn accordingly." | |||
| 2639 | do | 2828 | do |
| 2640 | (cl-assert (null (gethash idx reverse-h))) | 2829 | (cl-assert (null (gethash idx reverse-h))) |
| 2641 | (cl-assert (fixnump idx)) | 2830 | (cl-assert (fixnump idx)) |
| 2642 | (setf (comp-mvar-constant mvar) idx) | 2831 | (setf (comp-mvar-valset mvar) () |
| 2832 | (comp-mvar-range mvar) (list (cons idx idx))) | ||
| 2643 | (puthash idx t reverse-h)))) | 2833 | (puthash idx t reverse-h)))) |
| 2644 | 2834 | ||
| 2645 | (defun comp-compile-ctxt-to-file (name) | 2835 | (defun comp-compile-ctxt-to-file (name) |
diff --git a/src/comp.c b/src/comp.c index cb5f1a1ce96..0d464281858 100644 --- a/src/comp.c +++ b/src/comp.c | |||
| @@ -1845,32 +1845,32 @@ emit_PURE_P (gcc_jit_rvalue *ptr) | |||
| 1845 | static gcc_jit_rvalue * | 1845 | static gcc_jit_rvalue * |
| 1846 | emit_mvar_rval (Lisp_Object mvar) | 1846 | emit_mvar_rval (Lisp_Object mvar) |
| 1847 | { | 1847 | { |
| 1848 | Lisp_Object const_vld = CALL1I (comp-mvar-const-vld, mvar); | 1848 | Lisp_Object const_vld = CALL1I (comp-mvar-value-vld-p, mvar); |
| 1849 | Lisp_Object constant = CALL1I (comp-mvar-constant, mvar); | ||
| 1850 | 1849 | ||
| 1851 | if (!NILP (const_vld)) | 1850 | if (!NILP (const_vld)) |
| 1852 | { | 1851 | { |
| 1852 | Lisp_Object value = CALL1I (comp-mvar-value, mvar); | ||
| 1853 | if (comp.debug > 1) | 1853 | if (comp.debug > 1) |
| 1854 | { | 1854 | { |
| 1855 | Lisp_Object func = | 1855 | Lisp_Object func = |
| 1856 | Fgethash (constant, | 1856 | Fgethash (value, |
| 1857 | CALL1I (comp-ctxt-byte-func-to-func-h, Vcomp_ctxt), | 1857 | CALL1I (comp-ctxt-byte-func-to-func-h, Vcomp_ctxt), |
| 1858 | Qnil); | 1858 | Qnil); |
| 1859 | 1859 | ||
| 1860 | emit_comment ( | 1860 | emit_comment ( |
| 1861 | SSDATA ( | 1861 | SSDATA ( |
| 1862 | Fprin1_to_string ( | 1862 | Fprin1_to_string ( |
| 1863 | NILP (func) ? constant : CALL1I (comp-func-c-name, func), | 1863 | NILP (func) ? value : CALL1I (comp-func-c-name, func), |
| 1864 | Qnil))); | 1864 | Qnil))); |
| 1865 | } | 1865 | } |
| 1866 | if (FIXNUMP (constant)) | 1866 | if (FIXNUMP (value)) |
| 1867 | { | 1867 | { |
| 1868 | /* We can still emit directly objects that are self-contained in a | 1868 | /* We can still emit directly objects that are self-contained in a |
| 1869 | word (read fixnums). */ | 1869 | word (read fixnums). */ |
| 1870 | return emit_rvalue_from_lisp_obj (constant); | 1870 | return emit_rvalue_from_lisp_obj (value); |
| 1871 | } | 1871 | } |
| 1872 | /* Other const objects are fetched from the reloc array. */ | 1872 | /* Other const objects are fetched from the reloc array. */ |
| 1873 | return emit_lisp_obj_rval (constant); | 1873 | return emit_lisp_obj_rval (value); |
| 1874 | } | 1874 | } |
| 1875 | 1875 | ||
| 1876 | return gcc_jit_lvalue_as_rvalue (emit_mvar_lval (mvar)); | 1876 | return gcc_jit_lvalue_as_rvalue (emit_mvar_lval (mvar)); |
| @@ -2371,12 +2371,13 @@ static gcc_jit_rvalue * | |||
| 2371 | emit_call_with_type_hint (gcc_jit_function *func, Lisp_Object insn, | 2371 | emit_call_with_type_hint (gcc_jit_function *func, Lisp_Object insn, |
| 2372 | Lisp_Object type) | 2372 | Lisp_Object type) |
| 2373 | { | 2373 | { |
| 2374 | bool type_hint = EQ (CALL1I (comp-mvar-type, SECOND (insn)), type); | 2374 | bool hint_match = |
| 2375 | !NILP (CALL2I (comp-mvar-type-hint-match-p, SECOND (insn), type)); | ||
| 2375 | gcc_jit_rvalue *args[] = | 2376 | gcc_jit_rvalue *args[] = |
| 2376 | { emit_mvar_rval (SECOND (insn)), | 2377 | { emit_mvar_rval (SECOND (insn)), |
| 2377 | gcc_jit_context_new_rvalue_from_int (comp.ctxt, | 2378 | gcc_jit_context_new_rvalue_from_int (comp.ctxt, |
| 2378 | comp.bool_type, | 2379 | comp.bool_type, |
| 2379 | type_hint) }; | 2380 | hint_match) }; |
| 2380 | 2381 | ||
| 2381 | return gcc_jit_context_new_call (comp.ctxt, NULL, func, 2, args); | 2382 | return gcc_jit_context_new_call (comp.ctxt, NULL, func, 2, args); |
| 2382 | } | 2383 | } |
| @@ -2386,13 +2387,14 @@ static gcc_jit_rvalue * | |||
| 2386 | emit_call2_with_type_hint (gcc_jit_function *func, Lisp_Object insn, | 2387 | emit_call2_with_type_hint (gcc_jit_function *func, Lisp_Object insn, |
| 2387 | Lisp_Object type) | 2388 | Lisp_Object type) |
| 2388 | { | 2389 | { |
| 2389 | bool type_hint = EQ (CALL1I (comp-mvar-type, SECOND (insn)), type); | 2390 | bool hint_match = |
| 2391 | !NILP (CALL2I (comp-mvar-type-hint-match-p, SECOND (insn), type)); | ||
| 2390 | gcc_jit_rvalue *args[] = | 2392 | gcc_jit_rvalue *args[] = |
| 2391 | { emit_mvar_rval (SECOND (insn)), | 2393 | { emit_mvar_rval (SECOND (insn)), |
| 2392 | emit_mvar_rval (THIRD (insn)), | 2394 | emit_mvar_rval (THIRD (insn)), |
| 2393 | gcc_jit_context_new_rvalue_from_int (comp.ctxt, | 2395 | gcc_jit_context_new_rvalue_from_int (comp.ctxt, |
| 2394 | comp.bool_type, | 2396 | comp.bool_type, |
| 2395 | type_hint) }; | 2397 | hint_match) }; |
| 2396 | 2398 | ||
| 2397 | return gcc_jit_context_new_call (comp.ctxt, NULL, func, 3, args); | 2399 | return gcc_jit_context_new_call (comp.ctxt, NULL, func, 3, args); |
| 2398 | } | 2400 | } |
diff --git a/test/src/comp-tests.el b/test/src/comp-tests.el index 21c8abad038..48687d92021 100644 --- a/test/src/comp-tests.el +++ b/test/src/comp-tests.el | |||
| @@ -37,7 +37,7 @@ | |||
| 37 | (defconst comp-test-dyn-src | 37 | (defconst comp-test-dyn-src |
| 38 | (concat comp-test-directory "comp-test-funcs-dyn.el")) | 38 | (concat comp-test-directory "comp-test-funcs-dyn.el")) |
| 39 | 39 | ||
| 40 | (when (boundp 'comp-ctxt) | 40 | (when (featurep 'nativecomp) |
| 41 | (message "Compiling tests...") | 41 | (message "Compiling tests...") |
| 42 | (load (native-compile comp-test-src)) | 42 | (load (native-compile comp-test-src)) |
| 43 | (load (native-compile comp-test-dyn-src))) | 43 | (load (native-compile comp-test-dyn-src))) |
| @@ -676,8 +676,8 @@ https://lists.gnu.org/archive/html/bug-gnu-emacs/2020-03/msg00914.html." | |||
| 676 | (cl-loop for y in insn | 676 | (cl-loop for y in insn |
| 677 | when (cond | 677 | when (cond |
| 678 | ((consp y) (comp-tests-mentioned-p x y)) | 678 | ((consp y) (comp-tests-mentioned-p x y)) |
| 679 | ((and (comp-mvar-p y) (comp-mvar-const-vld y)) | 679 | ((and (comp-mvar-p y) (comp-mvar-value-vld-p y)) |
| 680 | (equal (comp-mvar-constant y) x)) | 680 | (equal (comp-mvar-value y) x)) |
| 681 | (t (equal x y))) | 681 | (t (equal x y))) |
| 682 | return t)) | 682 | return t)) |
| 683 | 683 | ||
| @@ -804,8 +804,8 @@ Return a list of results." | |||
| 804 | (lambda (insn) | 804 | (lambda (insn) |
| 805 | (pcase insn | 805 | (pcase insn |
| 806 | (`(return ,mvar) | 806 | (`(return ,mvar) |
| 807 | (and (comp-mvar-const-vld mvar) | 807 | (and (comp-mvar-value-vld-p mvar) |
| 808 | (= (comp-mvar-constant mvar) 123))))))))) | 808 | (eql (comp-mvar-value mvar) 123))))))))) |
| 809 | 809 | ||
| 810 | (defvar comp-tests-cond-rw-expected-type nil | 810 | (defvar comp-tests-cond-rw-expected-type nil |
| 811 | "Type to expect in `comp-tests-cond-rw-checker-type'.") | 811 | "Type to expect in `comp-tests-cond-rw-checker-type'.") |
| @@ -819,7 +819,8 @@ Return a list of results." | |||
| 819 | (lambda (insn) | 819 | (lambda (insn) |
| 820 | (pcase insn | 820 | (pcase insn |
| 821 | (`(return ,mvar) | 821 | (`(return ,mvar) |
| 822 | (eq (comp-mvar-type mvar) comp-tests-cond-rw-expected-type)))))))) | 822 | (equal (comp-mvar-typeset mvar) |
| 823 | comp-tests-cond-rw-expected-type)))))))) | ||
| 823 | 824 | ||
| 824 | (defvar comp-tests-cond-rw-0-var) | 825 | (defvar comp-tests-cond-rw-0-var) |
| 825 | (comp-deftest cond-rw-0 () | 826 | (comp-deftest cond-rw-0 () |
| @@ -839,40 +840,39 @@ Return a list of results." | |||
| 839 | (comp-deftest cond-rw-1 () | 840 | (comp-deftest cond-rw-1 () |
| 840 | "Test cond-rw pass allow us to propagate type+val under `eq' tests." | 841 | "Test cond-rw pass allow us to propagate type+val under `eq' tests." |
| 841 | (let ((lexical-binding t) | 842 | (let ((lexical-binding t) |
| 842 | (comp-tests-cond-rw-expected-type 'fixnum) | 843 | (comp-tests-cond-rw-expected-type '(integer)) |
| 843 | (comp-post-pass-hooks '((comp-final comp-tests-cond-rw-checker-type) | 844 | (comp-post-pass-hooks '((comp-final comp-tests-cond-rw-checker-type |
| 844 | (comp-final comp-tests-cond-rw-checker-val)))) | 845 | comp-tests-cond-rw-checker-val)))) |
| 845 | (subr-native-elisp-p (native-compile '(lambda (x) (if (eq x 123) x t)))) | 846 | (subr-native-elisp-p (native-compile '(lambda (x) (if (eq x 123) x t)))) |
| 846 | (subr-native-elisp-p (native-compile '(lambda (x) (if (eq 123 x) x t)))))) | 847 | (subr-native-elisp-p (native-compile '(lambda (x) (if (eq 123 x) x t)))))) |
| 847 | 848 | ||
| 848 | (comp-deftest cond-rw-2 () | 849 | (comp-deftest cond-rw-2 () |
| 849 | "Test cond-rw pass allow us to propagate type+val under `=' tests." | 850 | "Test cond-rw pass allow us to propagate type+val under `=' tests." |
| 850 | (let ((lexical-binding t) | 851 | (let ((lexical-binding t) |
| 851 | (comp-tests-cond-rw-expected-type 'fixnum) | 852 | (comp-tests-cond-rw-expected-type '(integer)) |
| 852 | (comp-post-pass-hooks '((comp-final comp-tests-cond-rw-checker-type) | 853 | (comp-post-pass-hooks '((comp-final comp-tests-cond-rw-checker-type |
| 853 | (comp-final comp-tests-cond-rw-checker-val)))) | 854 | comp-tests-cond-rw-checker-val)))) |
| 854 | (subr-native-elisp-p (native-compile '(lambda (x) (if (= x 123) x t)))))) | 855 | (subr-native-elisp-p (native-compile '(lambda (x) (if (= x 123) x t)))))) |
| 855 | 856 | ||
| 856 | (comp-deftest cond-rw-3 () | 857 | (comp-deftest cond-rw-3 () |
| 857 | "Test cond-rw pass allow us to propagate type+val under `eql' tests." | 858 | "Test cond-rw pass allow us to propagate type+val under `eql' tests." |
| 858 | (let ((lexical-binding t) | 859 | (let ((lexical-binding t) |
| 859 | (comp-tests-cond-rw-expected-type 'fixnum) | 860 | (comp-tests-cond-rw-expected-type '(integer)) |
| 860 | (comp-post-pass-hooks '((comp-final comp-tests-cond-rw-checker-type) | 861 | (comp-post-pass-hooks '((comp-final comp-tests-cond-rw-checker-type |
| 861 | (comp-final comp-tests-cond-rw-checker-val)))) | 862 | comp-tests-cond-rw-checker-val)))) |
| 862 | (subr-native-elisp-p (native-compile '(lambda (x) (if (eql 123 x) x t)))))) | 863 | (subr-native-elisp-p (native-compile '(lambda (x) (if (eql 123 x) x t)))))) |
| 863 | 864 | ||
| 864 | (comp-deftest cond-rw-4 () | 865 | (comp-deftest cond-rw-4 () |
| 865 | "Test cond-rw pass allow us to propagate type under `=' tests." | 866 | "Test cond-rw pass allow us to propagate type under `=' tests." |
| 866 | (let ((lexical-binding t) | 867 | (let ((lexical-binding t) |
| 867 | (comp-tests-cond-rw-expected-type 'number) | 868 | (comp-tests-cond-rw-expected-type '(number)) |
| 868 | (comp-post-pass-hooks '((comp-final comp-tests-cond-rw-checker-type)))) | 869 | (comp-post-pass-hooks '((comp-final comp-tests-cond-rw-checker-type)))) |
| 869 | (subr-native-elisp-p (native-compile '(lambda (x y) (if (= x y) x t)))))) | 870 | (subr-native-elisp-p (native-compile '(lambda (x y) (if (= x y) x t)))))) |
| 870 | 871 | ||
| 871 | (comp-deftest cond-rw-5 () | 872 | (comp-deftest cond-rw-5 () |
| 872 | "Test cond-rw pass allow us to propagate type under `=' tests." | 873 | "Test cond-rw pass allow us to propagate type under `=' tests." |
| 873 | (let ((lexical-binding t) | 874 | (let ((comp-tests-cond-rw-checked-function #'comp-tests-cond-rw-4-f) |
| 874 | (comp-tests-cond-rw-checked-function #'comp-tests-cond-rw-4-f) | 875 | (comp-tests-cond-rw-expected-type '(integer)) |
| 875 | (comp-tests-cond-rw-expected-type 'fixnum) | ||
| 876 | (comp-post-pass-hooks '((comp-final comp-tests-cond-rw-checker-type)))) | 876 | (comp-post-pass-hooks '((comp-final comp-tests-cond-rw-checker-type)))) |
| 877 | (eval '(defun comp-tests-cond-rw-4-f (x y) | 877 | (eval '(defun comp-tests-cond-rw-4-f (x y) |
| 878 | (declare (speed 3)) | 878 | (declare (speed 3)) |
| @@ -883,4 +883,48 @@ Return a list of results." | |||
| 883 | (native-compile #'comp-tests-cond-rw-4-f) | 883 | (native-compile #'comp-tests-cond-rw-4-f) |
| 884 | (should (subr-native-elisp-p (symbol-function #'comp-tests-cond-rw-4-f))))) | 884 | (should (subr-native-elisp-p (symbol-function #'comp-tests-cond-rw-4-f))))) |
| 885 | 885 | ||
| 886 | |||
| 887 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 888 | ;; Range propagation tests. ;; | ||
| 889 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 890 | |||
| 891 | (comp-deftest range-simple-union () | ||
| 892 | (should (equal (comp-range-union '((-1 . 0)) '((3 . 4))) | ||
| 893 | '((-1 . 0) (3 . 4)))) | ||
| 894 | (should (equal (comp-range-union '((-1 . 2)) '((3 . 4))) | ||
| 895 | '((-1 . 4)))) | ||
| 896 | (should (equal (comp-range-union '((-1 . 3)) '((3 . 4))) | ||
| 897 | '((-1 . 4)))) | ||
| 898 | (should (equal (comp-range-union '((-1 . 4)) '((3 . 4))) | ||
| 899 | '((-1 . 4)))) | ||
| 900 | (should (equal (comp-range-union '((-1 . 5)) '((3 . 4))) | ||
| 901 | '((-1 . 5)))) | ||
| 902 | (should (equal (comp-range-union '((-1 . 0)) '()) | ||
| 903 | '((-1 . 0))))) | ||
| 904 | |||
| 905 | (comp-deftest range-simple-intersection () | ||
| 906 | (should (equal (comp-range-intersection '((-1 . 0)) '((3 . 4))) | ||
| 907 | '())) | ||
| 908 | (should (equal (comp-range-intersection '((-1 . 2)) '((3 . 4))) | ||
| 909 | '())) | ||
| 910 | (should (equal (comp-range-intersection '((-1 . 3)) '((3 . 4))) | ||
| 911 | '((3 . 3)))) | ||
| 912 | (should (equal (comp-range-intersection '((-1 . 4)) '((3 . 4))) | ||
| 913 | '((3 . 4)))) | ||
| 914 | (should (equal (comp-range-intersection '((-1 . 5)) '((3 . 4))) | ||
| 915 | '((3 . 4)))) | ||
| 916 | (should (equal (comp-range-intersection '((-1 . 0)) '()) | ||
| 917 | '()))) | ||
| 918 | |||
| 919 | (comp-deftest union-types () | ||
| 920 | (let ((comp-ctxt (make-comp-ctxt))) | ||
| 921 | (should (equal (comp-union-typesets '(integer) '(number)) | ||
| 922 | '(number))) | ||
| 923 | (should (equal (comp-union-typesets '(integer symbol) '(number)) | ||
| 924 | '(symbol number))) | ||
| 925 | (should (equal (comp-union-typesets '(integer symbol) '(number list)) | ||
| 926 | '(list symbol number))) | ||
| 927 | (should (equal (comp-union-typesets '(integer symbol) '()) | ||
| 928 | '(symbol integer))))) | ||
| 929 | |||
| 886 | ;;; comp-tests.el ends here | 930 | ;;; comp-tests.el ends here |