emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/native-comp 89d5a3a: Enable integer range narrowing under compar


From: Andrea Corallo
Subject: feature/native-comp 89d5a3a: Enable integer range narrowing under compare and branch
Date: Sat, 26 Dec 2020 04:54:26 -0500 (EST)

branch: feature/native-comp
commit 89d5a3a7603a0b096d02f58ba0a1997ad98c63ae
Author: Andrea Corallo <akrl@sdf.org>
Commit: Andrea Corallo <akrl@sdf.org>

    Enable integer range narrowing under compare and branch
    
        * lisp/emacs-lisp/comp-cstr.el (comp-cstr-set-cmp-range)
        (comp-cstr->, comp-cstr->=, comp-cstr-<, comp-cstr-<=): New
        functions.
        * lisp/emacs-lisp/comp.el (comp-equality-fun-p)
        (comp-range-cmp-fun-p): New functions.
        (comp-collect-rhs): Use `comp-assign-op-p' in place of
        `comp-set-op-p'.
        (comp-negate-range-cmp-fun, comp-reverse-cmp-fun): New functions.
        (comp-emit-assume): Rework to be able to emit also comparision
        assumption.
        (comp-add-cond-cstrs-simple): Update for new `comp-emit-assume'.
        (comp-add-cond-cstrs-simple): Update to emit range assumption.
        (comp-fwprop-insn): Execute range assumptions.
        * test/src/comp-tests.el (comp-tests-type-spec-tests): Add tests.
---
 lisp/emacs-lisp/comp-cstr.el |  68 +++++++++++++++++++++++++++++
 lisp/emacs-lisp/comp.el      | 102 +++++++++++++++++++++++++++++++++----------
 test/src/comp-tests.el       |  77 +++++++++++++++++++++++++++++++-
 3 files changed, 224 insertions(+), 23 deletions(-)

diff --git a/lisp/emacs-lisp/comp-cstr.el b/lisp/emacs-lisp/comp-cstr.el
index 32989f2..9d0c671 100644
--- a/lisp/emacs-lisp/comp-cstr.el
+++ b/lisp/emacs-lisp/comp-cstr.el
@@ -362,6 +362,22 @@ Return them as multiple value."
        (push `(,(1+ last-h) . +) res))
      (cl-return (reverse res)))))
 
+(defsubst comp-cstr-set-cmp-range (dst old-dst ext-range)
+  "Support range comparison functions."
+  (with-comp-cstr-accessors
+    (if ext-range
+        (setf (typeset dst) ()
+              (valset dst) ()
+              (range dst) (if (range old-dst)
+                              (comp-range-intersection (range old-dst)
+                                                       ext-range)
+                            ext-range)
+              (neg dst) nil)
+      (setf (typeset dst) (typeset old-dst)
+            (valset dst) (valset old-dst)
+            (range dst) (range old-dst)
+            (neg dst) (neg old-dst)))))
+
 
 ;;; Union specific code.
 
@@ -663,6 +679,58 @@ Non memoized version of `comp-cstr-intersection-no-mem'."
 
 ;;; Entry points.
 
+(defun comp-cstr-> (dst old-dst src)
+  "Constraint DST being > than SRC.
+SRC can be either a comp-cstr or an integer."
+  (with-comp-cstr-accessors
+    (let ((ext-range
+           (if (integerp src)
+               `((,(1+ src) . +))
+             (when-let* ((range (range src))
+                         (low (cdar (last range)))
+                         (okay (integerp low)))
+               `((,(1+ low) . +))))))
+      (comp-cstr-set-cmp-range dst old-dst ext-range))))
+
+(defun comp-cstr->= (dst old-dst src)
+  "Constraint DST being >= than SRC.
+SRC can be either a comp-cstr or an integer."
+  (with-comp-cstr-accessors
+    (let ((ext-range
+           (if (integerp src)
+               `((,src . +))
+             (when-let* ((range (range src))
+                         (low (cdar (last range)))
+                         (okay (integerp low)))
+               `((,low . +))))))
+      (comp-cstr-set-cmp-range dst old-dst ext-range))))
+
+(defun comp-cstr-< (dst old-dst src)
+  "Constraint DST being < than SRC.
+SRC can be either a comp-cstr or an integer."
+  (with-comp-cstr-accessors
+    (let ((ext-range
+           (if (integerp src)
+               `((- . ,(1- src)))
+             (when-let* ((range (range src))
+                         (low (caar (last range)))
+                         (okay (integerp low)))
+               `((- . ,(1- low)))))))
+      (comp-cstr-set-cmp-range dst old-dst ext-range))))
+
+(defun comp-cstr-<= (dst old-dst src)
+  "Constraint DST being > than SRC.
+SRC can be either a comp-cstr or an integer."
+  (with-comp-cstr-accessors
+    (let ((ext-range
+           (if (integerp src)
+               `((- . ,src))
+             (when-let* ((range (range src))
+                         (low (caar (last range)))
+                         (okay (integerp low)))
+               `((- . ,low))))))
+      (comp-cstr-set-cmp-range dst old-dst ext-range))))
+
 (defun comp-cstr-union-no-range (dst &rest srcs)
   "Combine SRCS by union set operation setting the result in DST.
 Do not propagate the range component.
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el
index 1804f1f..7d444af 100644
--- a/lisp/emacs-lisp/comp.el
+++ b/lisp/emacs-lisp/comp.el
@@ -597,6 +597,14 @@ To be used by all entry points."
    ((null (native-comp-available-p))
     (error "Cannot find libgccjit"))))
 
+(defun comp-equality-fun-p (function)
+  "Equality functions predicate for FUNCTION."
+  (when (memq function '(eq eql = equal)) t))
+
+(defun comp-range-cmp-fun-p (function)
+  "Predicate for range comparision functions."
+  (when (memq function '(> < >= <=)) t))
+
 (defun comp-set-op-p (op)
   "Assignment predicate for OP."
   (when (memq op comp-limple-sets) t))
@@ -1876,7 +1884,10 @@ into the C code forwarding the compilation unit."
 ;; generated from:
 ;;
 ;;  - Conditional branches: each branch taken or non taken can be used
-;;    in the CFG to infer infomations 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
+;;    arithmetic comparison.)
 ;;
 ;;  - Function calls: function calls to function assumed to be not
 ;;    redefinable can be used to add constrains on the function
@@ -1907,25 +1918,58 @@ into the C code forwarding the compilation unit."
    do (cl-loop
        for insn in (comp-block-insns b)
        for (op . args) = insn
-       if  (comp-set-op-p op)
+       if (comp-assign-op-p op)
          do (comp-collect-mvars (cdr args))
        else
          do (comp-collect-mvars args))))
 
-(defun comp-emit-assume (lhs rhs bb negated)
-  "Emit an assume for mvar LHS being RHS.
+(defun comp-negate-range-cmp-fun (function)
+  "Negate FUNCTION."
+  (cl-ecase function
+    (> '<=)
+    (< '>=)
+    (>= '<)
+    (<= '>)))
+
+(defun comp-reverse-cmp-fun (function)
+  "Reverse FUNCTION."
+  (cl-case function
+    (> '<)
+    (< '>)
+    (>= '<=)
+    (<= '>=)
+    (t function)))
+
+(defun comp-emit-assume (kind lhs rhs bb negated)
+  "Emit an assume of kind KIND for mvar LHS being RHS.
 When NEGATED is non-nil the assumption is negated.
 The assume is emitted at the beginning of the block BB."
-  (let ((lhs-slot (comp-mvar-slot lhs))
-        (tmp-mvar (if negated
-                      (make-comp-mvar :slot (comp-mvar-slot rhs))
-                    rhs)))
+  (let ((lhs-slot (comp-mvar-slot lhs)))
     (cl-assert lhs-slot)
-    (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)))
+    (pcase kind
+      ('and
+       (let ((tmp-mvar (if negated
+                          (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)))))
+      ((pred comp-range-cmp-fun-p)
+       (let ((kind (if negated
+                       (comp-negate-range-cmp-fun kind)
+                     kind)))
+         (push `(assume ,(make-comp-mvar :slot lhs-slot)
+                        (,kind ,lhs
+                               ,(if-let* ((vld (comp-mvar-value-vld-p rhs))
+                                          (val (comp-mvar-value rhs))
+                                          (ok (integerp val)))
+                                    val
+                                  (make-comp-mvar :slot (comp-mvar-slot 
rhs)))))
+              (comp-block-insns bb))))
+      (_ (cl-assert nil)))
     (setf (comp-func-ssa-status comp-func) 'dirty)))
 
 (defun comp-add-new-block-between (bb-symbol bb-a bb-b)
@@ -2012,7 +2056,7 @@ TARGET-BB-SYM is the symbol name of the target block."
         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 tmp-mvar obj2 block-target negated))
+          (comp-emit-assume 'and tmp-mvar obj2 block-target negated))
         finally (cl-return-from in-the-basic-block)))
       (`((cond-jump ,obj1 ,obj2 . ,blocks))
        (cl-loop
@@ -2023,7 +2067,7 @@ TARGET-BB-SYM is the symbol name of the target block."
         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 obj1 obj2 block-target negated))
+          (comp-emit-assume 'and obj1 obj2 block-target negated))
         finally (cl-return-from in-the-basic-block)))))))
 
 (defun comp-add-cond-cstrs ()
@@ -2036,26 +2080,32 @@ TARGET-BB-SYM is the symbol name of the target block."
     for insns-seq on (comp-block-insns b)
     do
     (pcase insns-seq
-      (`((set ,(and (pred comp-mvar-p) obj1)
+      (`((set ,(and (pred comp-mvar-p) cmp-res)
               (,(pred comp-call-op-p)
-               ,(or 'eq 'eql '= 'equal) ,op1 ,op2))
+               ,(and (or (pred comp-equality-fun-p)
+                         (pred comp-range-cmp-fun-p))
+                     fun)
+               ,op1 ,op2))
         ;; (comment ,_comment-str)
-        (cond-jump ,obj1 ,(pred comp-mvar-p) . ,blocks))
+        (cond-jump ,cmp-res ,(pred comp-mvar-p) . ,blocks))
        (cl-loop
         with target-mvar1 = (comp-cond-cstrs-target-mvar op1 (car insns-seq) b)
         with target-mvar2 = (comp-cond-cstrs-target-mvar op2 (car insns-seq) b)
+        with equality = (comp-equality-fun-p fun)
         for branch-target-cell on blocks
         for branch-target = (car branch-target-cell)
         for negated in '(t nil)
+        for kind = (if equality 'and fun)
         when (or (comp-mvar-used-p target-mvar1)
                  (comp-mvar-used-p target-mvar2))
         do
         (let ((block-target (comp-add-cond-cstrs-target-block b 
branch-target)))
           (setf (car branch-target-cell) (comp-block-name block-target))
           (when (comp-mvar-used-p target-mvar1)
-            (comp-emit-assume target-mvar1 op2 block-target negated))
+            (comp-emit-assume kind target-mvar1 op2 block-target negated))
           (when (comp-mvar-used-p target-mvar2)
-            (comp-emit-assume target-mvar2 op1 block-target negated)))
+            (comp-emit-assume (comp-reverse-cmp-fun kind)
+                              target-mvar2 op1 block-target negated)))
         finally (cl-return-from in-the-basic-block)))))))
 
 (defun comp-emit-call-cstr (mvar call-cell cstr)
@@ -2610,13 +2660,21 @@ Fold the call in case."
        (_
         (comp-mvar-propagate lval rval))))
     (`(assume ,lval (,kind . ,operands))
-     (cl-ecase kind
+     (cl-case kind
        (and
         (apply #'comp-cstr-intersection lval operands))
        (not
         ;; Prevent double negation!
         (unless (comp-cstr-neg (car operands))
-          (comp-cstr-value-negation lval (car operands))))))
+          (comp-cstr-value-negation lval (car operands))))
+       (>
+        (comp-cstr-> lval (car operands) (cadr operands)))
+       (>=
+        (comp-cstr->= lval (car operands) (cadr operands)))
+       (<
+        (comp-cstr-< lval (car operands) (cadr operands)))
+       (<=
+        (comp-cstr-<= lval (car operands) (cadr operands)))))
     (`(setimm ,lval ,v)
      (setf (comp-mvar-value lval) v))
     (`(phi ,lval . ,rest)
diff --git a/test/src/comp-tests.el b/test/src/comp-tests.el
index 8f0b340..22065f8 100644
--- a/test/src/comp-tests.el
+++ b/test/src/comp-tests.el
@@ -947,7 +947,82 @@ Return a list of results."
       ((defun comp-tests-ret-type-spec-f (x)
          (unless x
            'foo))
-       (or (member foo) null))))
+       (or (member foo) null))
+
+      ;; 22
+      ((defun comp-tests-ret-type-spec-f (x)
+         (when (> x 3)
+           x))
+       (or null (integer 4 *)))
+
+      ;; 23
+      ((defun comp-tests-ret-type-spec-f (x)
+         (when (>= x 3)
+           x))
+       (or null (integer 3 *)))
+
+      ;; 24
+      ((defun comp-tests-ret-type-spec-f (x)
+         (when (< x 3)
+           x))
+       (or null (integer * 2)))
+
+      ;; 25
+      ((defun comp-tests-ret-type-spec-f (x)
+         (when (<= x 3)
+           x))
+       (or null (integer * 3)))
+
+      ;; 26
+      ((defun comp-tests-ret-type-spec-f (x)
+         (when (> 3 x)
+           x))
+       (or null (integer * 2)))
+
+      ;; 27
+      ((defun comp-tests-ret-type-spec-f (x)
+         (when (>= 3 x)
+           x))
+       (or null (integer * 3)))
+
+      ;; 28
+      ((defun comp-tests-ret-type-spec-f (x)
+         (when (< 3 x)
+           x))
+       (or null (integer 4 *)))
+
+      ;; 29
+      ((defun comp-tests-ret-type-spec-f (x)
+         (when (<= 3 x)
+           x))
+       (or null (integer 3 *)))
+
+      ;; 30
+      ((defun comp-tests-ret-type-spec-f (x)
+         (let ((y 3))
+          (when (> x y)
+            x)))
+       (or null (integer 4 *)))
+
+      ;; 31
+      ((defun comp-tests-ret-type-spec-f (x)
+         (let ((y 3))
+          (when (> y x)
+            x)))
+       (or null (integer * 2)))
+
+      ;; 32
+      ((defun comp-tests-ret-type-spec-f (x)
+         (when (and (> x 3)
+                   (< x 10))
+          x))
+       (or null (integer 4 9)))
+
+      ;; 33 No float range support.
+      ((defun comp-tests-ret-type-spec-f (x)
+              (when (> x 1.0)
+                x))
+       (or null marker number))))
 
   (defun comp-tests-define-type-spec-test (number x)
     `(comp-deftest ,(intern (format "ret-type-spec-%d" number)) ()



reply via email to

[Prev in Thread] Current Thread [Next in Thread]