aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/emacs-lisp/cl-preloaded.el3
-rw-r--r--lisp/emacs-lisp/comp.el350
-rw-r--r--src/comp.c24
-rw-r--r--test/src/comp-tests.el82
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.")
191Each function in FUNCTIONS is run after PASS. 191Each function in FUNCTIONS is run after PASS.
192Useful to hook into pass checkers.") 192Useful 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 436Each 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 439Interg 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.
492In 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)
1845static gcc_jit_rvalue * 1845static gcc_jit_rvalue *
1846emit_mvar_rval (Lisp_Object mvar) 1846emit_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 *
2371emit_call_with_type_hint (gcc_jit_function *func, Lisp_Object insn, 2371emit_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 *
2386emit_call2_with_type_hint (gcc_jit_function *func, Lisp_Object insn, 2387emit_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