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:
parent
e83c6994e1
commit
c4efb49a27
3 changed files with 123 additions and 26 deletions
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)) ()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue