1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-15 18:40:39 -08:00

Constrain mvars under compare and branch with built-in predicates

* lisp/emacs-lisp/comp.el (comp-emit-assume): Update.
	(comp-known-predicate-p): New function.
	(comp-add-cond-cstrs): Extend to pattern match predicate calls.
	* lisp/emacs-lisp/comp-cstr.el (comp-cstr-null-p)
	(comp-pred-to-cstr): New function.
	* test/src/comp-tests.el (comp-tests-type-spec-tests): Add a
	number of tests and fix comments.
This commit is contained in:
Andrea Corallo 2020-12-29 13:29:02 +01:00
parent e83c6994e1
commit c4efb49a27
3 changed files with 123 additions and 26 deletions

View file

@ -137,6 +137,13 @@ Integer values are handled in the `range' slot.")
(null (valset cstr)) (null (valset cstr))
(null (range cstr))))) (null (range cstr)))))
(defsubst comp-cstr-null-p (x)
"Return t if CSTR is equivalent to the `null' type specifier, nil otherwise."
(with-comp-cstr-accessors
(and (null (typeset x))
(null (range x))
(equal (valset x) '(nil)))))
(defun comp-cstrs-homogeneous (cstrs) (defun comp-cstrs-homogeneous (cstrs)
"Check if constraints CSTRS are all homogeneously negated or non-negated. "Check if constraints CSTRS are all homogeneously negated or non-negated.
Return `pos' if they are all positive, `neg' if they are all Return `pos' if they are all positive, `neg' if they are all
@ -167,6 +174,10 @@ Return them as multiple value."
:range '((1 . 1))) :range '((1 . 1)))
"Represent the integer immediate one (1).") "Represent the integer immediate one (1).")
(defun comp-pred-to-cstr (predicate)
"Given PREDICATE return the correspondig constraint."
(comp-type-to-cstr (get predicate 'cl-satisfies-deftype)))
;;; Value handling. ;;; Value handling.

View file

@ -1895,7 +1895,10 @@ into the C code forwarding the compilation unit."
;; in the CFG to infer information on the tested variables. ;; in the CFG to infer information on the tested variables.
;; ;;
;; - Range propagation under test and branch (when the test is an ;; - Range propagation under test and branch (when the test is an
;; arithmetic comparison.) ;; arithmetic comparison).
;;
;; - Type constraint under test and branch (when the test is a
;; known predicate).
;; ;;
;; - Function calls: function calls to function assumed to be not ;; - Function calls: function calls to function assumed to be not
;; redefinable can be used to add constrains on the function ;; redefinable can be used to add constrains on the function
@ -1956,15 +1959,22 @@ The assume is emitted at the beginning of the block BB."
(cl-assert lhs-slot) (cl-assert lhs-slot)
(pcase kind (pcase kind
('and ('and
(let ((tmp-mvar (if negated (if (comp-mvar-p rhs)
(make-comp-mvar :slot (comp-mvar-slot rhs)) (let ((tmp-mvar (if negated
rhs))) (make-comp-mvar :slot (comp-mvar-slot rhs))
rhs)))
(push `(assume ,(make-comp-mvar :slot lhs-slot)
(and ,lhs ,tmp-mvar))
(comp-block-insns bb))
(if negated
(push `(assume ,tmp-mvar (not ,rhs))
(comp-block-insns bb))))
;; If is only a constraint we can negate it directly.
(push `(assume ,(make-comp-mvar :slot lhs-slot) (push `(assume ,(make-comp-mvar :slot lhs-slot)
(and ,lhs ,tmp-mvar)) (and ,lhs ,(if negated
(comp-block-insns bb)) (comp-cstr-negation-make rhs)
(if negated rhs)))
(push `(assume ,tmp-mvar (not ,rhs)) (comp-block-insns bb))))
(comp-block-insns bb)))))
((pred comp-range-cmp-fun-p) ((pred comp-range-cmp-fun-p)
(let ((kind (if negated (let ((kind (if negated
(comp-negate-range-cmp-fun kind) (comp-negate-range-cmp-fun kind)
@ -2078,6 +2088,10 @@ TARGET-BB-SYM is the symbol name of the target block."
(comp-emit-assume 'and obj1 obj2 block-target negated)) (comp-emit-assume 'and obj1 obj2 block-target negated))
finally (cl-return-from in-the-basic-block))))))) finally (cl-return-from in-the-basic-block)))))))
(defun comp-known-predicate-p (pred)
(when (symbolp pred)
(get pred 'cl-satisfies-deftype)))
(defun comp-add-cond-cstrs () (defun comp-add-cond-cstrs ()
"`comp-add-cstrs' worker function for each selected function." "`comp-add-cstrs' worker function for each selected function."
(cl-loop (cl-loop
@ -2114,6 +2128,43 @@ TARGET-BB-SYM is the symbol name of the target block."
(when (comp-mvar-used-p target-mvar2) (when (comp-mvar-used-p target-mvar2)
(comp-emit-assume (comp-reverse-cmp-fun kind) (comp-emit-assume (comp-reverse-cmp-fun kind)
target-mvar2 op1 block-target negated))) target-mvar2 op1 block-target negated)))
finally (cl-return-from in-the-basic-block)))
(`((set ,(and (pred comp-mvar-p) cmp-res)
(,(pred comp-call-op-p)
,(and (pred comp-known-predicate-p) fun)
,op))
;; (comment ,_comment-str)
(cond-jump ,cmp-res ,(pred comp-mvar-p) . ,blocks))
(cl-loop
with target-mvar = (comp-cond-cstrs-target-mvar op (car insns-seq) b)
with cstr = (comp-pred-to-cstr fun)
for branch-target-cell on blocks
for branch-target = (car branch-target-cell)
for negated in '(t nil)
when (comp-mvar-used-p target-mvar)
do
(let ((block-target (comp-add-cond-cstrs-target-block b branch-target)))
(setf (car branch-target-cell) (comp-block-name block-target))
(comp-emit-assume 'and target-mvar cstr block-target negated))
finally (cl-return-from in-the-basic-block)))
;; Match predicate on the negated branch (unless).
(`((set ,(and (pred comp-mvar-p) cmp-res)
(,(pred comp-call-op-p)
,(and (pred comp-known-predicate-p) fun)
,op))
(set ,neg-cmp-res (call eq ,cmp-res ,(pred comp-cstr-null-p)))
(cond-jump ,neg-cmp-res ,(pred comp-mvar-p) . ,blocks))
(cl-loop
with target-mvar = (comp-cond-cstrs-target-mvar op (car insns-seq) b)
with cstr = (comp-pred-to-cstr fun)
for branch-target-cell on blocks
for branch-target = (car branch-target-cell)
for negated in '(nil t)
when (comp-mvar-used-p target-mvar)
do
(let ((block-target (comp-add-cond-cstrs-target-block b branch-target)))
(setf (car branch-target-cell) (comp-block-name block-target))
(comp-emit-assume 'and target-mvar cstr block-target negated))
finally (cl-return-from in-the-basic-block))))))) finally (cl-return-from in-the-basic-block)))))))
(defun comp-emit-call-cstr (mvar call-cell cstr) (defun comp-emit-call-cstr (mvar call-cell cstr)

View file

@ -837,7 +837,6 @@ Return a list of results."
y)) y))
(or (integer 1 1) (integer 3 3))) (or (integer 1 1) (integer 3 3)))
;; 6 ;; 6
((defun comp-tests-ret-type-spec-f (x) ((defun comp-tests-ret-type-spec-f (x)
(if x (if x
@ -1035,8 +1034,6 @@ Return a list of results."
(or null marker number)) (or null marker number))
;; 36 ;; 36
;; SBCL: (OR (RATIONAL (5)) (SINGLE-FLOAT 5.0)
;; (DOUBLE-FLOAT 5.0d0) NULL) !?
((defun comp-tests-ret-type-spec-f (x y) ((defun comp-tests-ret-type-spec-f (x y)
(when (and (> x 3) (when (and (> x 3)
(> y 2)) (> y 2))
@ -1051,15 +1048,14 @@ Return a list of results."
(+ x y))) (+ x y)))
(or null float (integer * 5))) (or null float (integer * 5)))
;; 38 SBCL gives: (OR (RATIONAL (2) (10)) (SINGLE-FLOAT 2.0 10.0) ;; 38
;; (DOUBLE-FLOAT 2.0d0 10.0d0) NULL)!?
((defun comp-tests-ret-type-spec-f (x y) ((defun comp-tests-ret-type-spec-f (x y)
(when (and (< 1 x 5) (when (and (< 1 x 5)
(< 1 y 5)) (< 1 y 5))
(+ x y))) (+ x y)))
(or null float (integer 4 8))) (or null float (integer 4 8)))
;; 37 ;; 39
;; SBCL gives: (OR REAL NULL) ;; SBCL gives: (OR REAL NULL)
((defun comp-tests-ret-type-spec-f (x y) ((defun comp-tests-ret-type-spec-f (x y)
(when (and (<= 1 x 10) (when (and (<= 1 x 10)
@ -1067,7 +1063,7 @@ Return a list of results."
(+ x y))) (+ x y)))
(or null float (integer 3 13))) (or null float (integer 3 13)))
;; 38 ;; 40
;; SBCL: (OR REAL NULL) ;; SBCL: (OR REAL NULL)
((defun comp-tests-ret-type-spec-f (x y) ((defun comp-tests-ret-type-spec-f (x y)
(when (and (<= 1 x 10) (when (and (<= 1 x 10)
@ -1075,42 +1071,42 @@ Return a list of results."
(- x y))) (- x y)))
(or null float (integer -2 8))) (or null float (integer -2 8)))
;; 39 ;; 41
((defun comp-tests-ret-type-spec-f (x y) ((defun comp-tests-ret-type-spec-f (x y)
(when (and (<= 1 x) (when (and (<= 1 x)
(<= 2 y 3)) (<= 2 y 3))
(- x y))) (- x y)))
(or null float (integer -2 *))) (or null float (integer -2 *)))
;; 40 ;; 42
((defun comp-tests-ret-type-spec-f (x y) ((defun comp-tests-ret-type-spec-f (x y)
(when (and (<= 1 x 10) (when (and (<= 1 x 10)
(<= 2 y)) (<= 2 y))
(- x y))) (- x y)))
(or null float (integer * 8))) (or null float (integer * 8)))
;; 41 ;; 43
((defun comp-tests-ret-type-spec-f (x y) ((defun comp-tests-ret-type-spec-f (x y)
(when (and (<= x 10) (when (and (<= x 10)
(<= 2 y)) (<= 2 y))
(- x y))) (- x y)))
(or null float (integer * 8))) (or null float (integer * 8)))
;; 42 ;; 44
((defun comp-tests-ret-type-spec-f (x y) ((defun comp-tests-ret-type-spec-f (x y)
(when (and (<= x 10) (when (and (<= x 10)
(<= y 3)) (<= y 3))
(- x y))) (- x y)))
(or null float integer)) (or null float integer))
;; 43 ;; 45
((defun comp-tests-ret-type-spec-f (x y) ((defun comp-tests-ret-type-spec-f (x y)
(when (and (<= 2 x) (when (and (<= 2 x)
(<= 3 y)) (<= 3 y))
(- x y))) (- x y)))
(or null float integer)) (or null float integer))
;; 44 ;; 46
;; SBCL: (OR (RATIONAL (6) (30)) (SINGLE-FLOAT 6.0 30.0) ;; SBCL: (OR (RATIONAL (6) (30)) (SINGLE-FLOAT 6.0 30.0)
;; (DOUBLE-FLOAT 6.0d0 30.0d0) NULL) ;; (DOUBLE-FLOAT 6.0d0 30.0d0) NULL)
((defun comp-tests-ret-type-spec-f (x y z i j k) ((defun comp-tests-ret-type-spec-f (x y z i j k)
@ -1123,22 +1119,61 @@ Return a list of results."
(+ x y z i j k))) (+ x y z i j k)))
(or null float (integer 12 24))) (or null float (integer 12 24)))
;; 45 ;; 47
((defun comp-tests-ret-type-spec-f (x) ((defun comp-tests-ret-type-spec-f (x)
(when (<= 1 x 5) (when (<= 1 x 5)
(1+ x))) (1+ x)))
(or null float (integer 2 6))) (or null float (integer 2 6)))
;;46 ;;48
((defun comp-tests-ret-type-spec-f (x) ((defun comp-tests-ret-type-spec-f (x)
(when (<= 1 x 5) (when (<= 1 x 5)
(1- x))) (1- x)))
(or null float (integer 0 4))) (or null float (integer 0 4)))
;; 47 ;; 49
((defun comp-tests-ret-type-spec-f () ((defun comp-tests-ret-type-spec-f ()
(error "foo")) (error "foo"))
nil))) nil)
;; 50
((defun comp-tests-ret-type-spec-f (x)
(if (stringp x)
x
'bar))
(or (member bar) string))
;; 51
((defun comp-tests-ret-type-spec-f (x)
(if (stringp x)
'bar
x))
(not string))
;; 52
((defun comp-tests-ret-type-spec-f (x)
(if (integerp x)
x
'bar))
(or (member bar) integer))
;; 53
((defun comp-tests-ret-type-spec-f (x)
(when (integerp x)
x))
(or null integer))
;; 54
((defun comp-tests-ret-type-spec-f (x)
(unless (symbolp x)
x))
(not symbol))
;; 55
((defun comp-tests-ret-type-spec-f (x)
(unless (integerp x)
x))
(not integer))))
(defun comp-tests-define-type-spec-test (number x) (defun comp-tests-define-type-spec-test (number x)
`(comp-deftest ,(intern (format "ret-type-spec-%d" number)) () `(comp-deftest ,(intern (format "ret-type-spec-%d" number)) ()