Compiler should use comparisons to restrict integer range types

Bug #1818442 reported by Paul F. Dietz on 2019-03-03
This bug affects 1 person
Affects Status Importance Assigned to Milestone

Bug Description

(defun f (i)
   (declare (type (integer 0) i))
            (optimize speed (safety 0)))
     ((= i 0) 'a)
     ((> i 0) 'b)
     (t 'c)))

does not conclude the T branch is dead.

; disassembly for F
; Size: 47 bytes. Origin: #x52DD60E6
; 0E6: 4885D2 TEST RDX, RDX ; no-arg-parsing entry point
; 0E9: 7421 JEQ L1
; 0ED: FF1425D8001052 CALL QWORD PTR [#x521000D8] ; GENERIC->
; 0F4: 488B0595FFFFFF MOV RAX, [RIP-107] ; 'B
; 0FB: 488B1596FFFFFF MOV RDX, [RIP-106] ; 'C
; 102: 480F4FD0 CMOVNLE RDX, RAX
; 106: L0: 488BE5 MOV RSP, RBP
; 109: F8 CLC
; 10A: 5D POP RBP
; 10B: C3 RET
; 10C: L1: 488B158DFFFFFF MOV RDX, [RIP-115] ; 'A
; 113: EBF1 JMP L0

The reason I want this is so we can insert ASSERT statements that the compiler can completely remove. These statements are useful for mutation testing, where a piece of lisp code is mutated to see if the mutations are caught by a test suite. Assertions can turn correctness-preserving mutations (which are useless for validating a test suite) into failing mutations. An example of this is mutation testing of tests for SBCL's implementation of LIST*, where the assert (assert (> length 1)) in the (t ...) clause of the COND helped suppress useless mutations.

Paul F. Dietz (paul-f-dietz) wrote :

If I change the first test there to (<= a 0), then the optimization works. This suggests to me that most of the logic is already there in the type propagator.

Paul F. Dietz (paul-f-dietz) wrote :

(<= i 0), I mean

Paul F. Dietz (paul-f-dietz) wrote :

For clarity, here's the modified LIST* function I was using for mutation testing of the LIST* tests in ansi-tests:

(defun my-list* (arg &rest others)
  "Return a list of the arguments with last cons a dotted pair."
  (let ((length (length others)))
    (cond ((= length 0) arg)
          ((= length 1)
           (cons arg (nth 0 others)))
           (assert (> length 1))
           (let* ((cons (list arg))
                  (result cons)
                  (1-length (1- length)))
             (let ((index 0))
                    ((< index 1-length)
                     (setf cons
                           (setf (cdr cons)
                                 (list (nth index others))))
                     (incf index))
                    (t (return)))))
             (setf (cdr cons) (nth 1-length others))

There are two changes here (aside from removing some internal function names): the (assert (> length 1)) that I'd like to have optimized away, and the change to use 1-length instead of index (and narrowing of the scope of index). This was to avoid a mutant that replaces index with 1-length in the penultimate line, which was a correctness-preserving change.

To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers