Compiler should use comparisons to restrict integer range types

Bug #1818442 reported by Paul F. Dietz
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
SBCL
Fix Released
Undecided
Unassigned

Bug Description

(defun f (i)
   (declare (type (integer 0) i))
            (optimize speed (safety 0)))
   (cond
     ((= 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
; 0EB: 31FF XOR EDI, EDI
; 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.

Revision history for this message
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.

Revision history for this message
Paul F. Dietz (paul-f-dietz) wrote :

(<= i 0), I mean

Revision history for this message
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)))
          (t
           (assert (> length 1))
           (let* ((cons (list arg))
                  (result cons)
                  (1-length (1- length)))
             (let ((index 0))
               (loop
                  (cond
                    ((< index 1-length)
                     (setf cons
                           (setf (cdr cons)
                                 (list (nth index others))))
                     (incf index))
                    (t (return)))))
             (setf (cdr cons) (nth 1-length others))
             result)))))

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.

Stas Boukarev (stassats)
Changed in sbcl:
status: New → Fix Committed
Stas Boukarev (stassats)
Changed in sbcl:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.