mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-30 15:00:21 +02:00
Fix bug in CSE auxiliary definitions
* module/language/cps/cse.scm (compute-equivalent-subexpressions): When CSE sees a definition like `(cons a b)', it will also record an "auxiliary definition" for `(car x)', where x is the variable defined by the cons, whereby calling `(car x)' can reduce to `a' if there is no intervening effect that clobbers the definitions. However, when the successor of the cons is a control-flow join, then any variables defined there have multiple definitions. It's incorrect to add the aux definition in that case. * test-suite/tests/compiler.test ("cse auxiliary definitions"): New test.
This commit is contained in:
parent
b02d1b08d7
commit
a2f5f9eda4
2 changed files with 56 additions and 16 deletions
|
@ -1,6 +1,6 @@
|
||||||
;;; Continuation-passing style (CPS) intermediate language (IL)
|
;;; Continuation-passing style (CPS) intermediate language (IL)
|
||||||
|
|
||||||
;; Copyright (C) 2013, 2014, 2015, 2017, 2018 Free Software Foundation, Inc.
|
;; Copyright (C) 2013-2019 Free Software Foundation, Inc.
|
||||||
|
|
||||||
;;;; This library is free software; you can redistribute it and/or
|
;;;; This library is free software; you can redistribute it and/or
|
||||||
;;;; modify it under the terms of the GNU Lesser General Public
|
;;;; modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -225,9 +225,8 @@ false. It could be that both true and false proofs are available."
|
||||||
(cons* op param (subst-vars var-substs args)))
|
(cons* op param (subst-vars var-substs args)))
|
||||||
((or ($ $prompt) ($ $throw)) #f)))
|
((or ($ $prompt) ($ $throw)) #f)))
|
||||||
|
|
||||||
(define (add-auxiliary-definitions! label var-substs term-key)
|
(define (add-auxiliary-definitions! label defs var-substs term-key)
|
||||||
(let ((defs (and=> (intmap-ref defs label)
|
(let ((defs (and defs (subst-vars var-substs defs))))
|
||||||
(lambda (defs) (subst-vars var-substs defs)))))
|
|
||||||
(define (add-def! aux-key var)
|
(define (add-def! aux-key var)
|
||||||
(let ((equiv (hash-ref equiv-set aux-key '())))
|
(let ((equiv (hash-ref equiv-set aux-key '())))
|
||||||
(hash-set! equiv-set aux-key
|
(hash-set! equiv-set aux-key
|
||||||
|
@ -242,6 +241,10 @@ false. It could be that both true and false proofs are available."
|
||||||
(match term-key
|
(match term-key
|
||||||
(('op arg ...)
|
(('op arg ...)
|
||||||
(match defs
|
(match defs
|
||||||
|
(#f
|
||||||
|
;; If the successor is a control-flow join, don't
|
||||||
|
;; pretend to know the values of its defs.
|
||||||
|
#f)
|
||||||
((def) (add-def! (list 'op* arg* ...) aux) ...)))
|
((def) (add-def! (list 'op* arg* ...) aux) ...)))
|
||||||
(_ (add-definitions . clauses))))
|
(_ (add-definitions . clauses))))
|
||||||
((add-definitions
|
((add-definitions
|
||||||
|
@ -296,13 +299,13 @@ false. It could be that both true and false proofs are available."
|
||||||
(let* ((equiv (hash-ref equiv-set term-key '()))
|
(let* ((equiv (hash-ref equiv-set term-key '()))
|
||||||
(fx (intmap-ref effects label))
|
(fx (intmap-ref effects label))
|
||||||
(avail (intmap-ref avail label)))
|
(avail (intmap-ref avail label)))
|
||||||
(define (finish equiv-labels var-substs)
|
(define (finish equiv-labels var-substs defs)
|
||||||
;; If this expression defines auxiliary definitions,
|
;; If this expression defines auxiliary definitions,
|
||||||
;; as `cons' does for the results of `car' and `cdr',
|
;; as `cons' does for the results of `car' and `cdr',
|
||||||
;; define those. Do so after finding equivalent
|
;; define those. Do so after finding equivalent
|
||||||
;; expressions, so that we can take advantage of
|
;; expressions, so that we can take advantage of
|
||||||
;; subst'd output vars.
|
;; subst'd output vars.
|
||||||
(add-auxiliary-definitions! label var-substs term-key)
|
(add-auxiliary-definitions! label defs var-substs term-key)
|
||||||
(values equiv-labels var-substs))
|
(values equiv-labels var-substs))
|
||||||
(let lp ((candidates equiv))
|
(let lp ((candidates equiv))
|
||||||
(match candidates
|
(match candidates
|
||||||
|
@ -314,13 +317,12 @@ false. It could be that both true and false proofs are available."
|
||||||
;; be eliminated by CSE (though DCE might do it
|
;; be eliminated by CSE (though DCE might do it
|
||||||
;; if the value proves to be unused, in the
|
;; if the value proves to be unused, in the
|
||||||
;; allocation case).
|
;; allocation case).
|
||||||
(when (and (not (causes-effect? fx &allocation))
|
|
||||||
(not (effect-clobbers? fx (&read-object &fluid))))
|
|
||||||
(let ((defs (term-defs term)))
|
(let ((defs (term-defs term)))
|
||||||
(when defs
|
(when (and defs
|
||||||
(hash-set! equiv-set term-key
|
(not (causes-effect? fx &allocation))
|
||||||
(acons label defs equiv)))))
|
(not (effect-clobbers? fx (&read-object &fluid))))
|
||||||
(finish equiv-labels var-substs))
|
(hash-set! equiv-set term-key (acons label defs equiv)))
|
||||||
|
(finish equiv-labels var-substs defs)))
|
||||||
(((and head (candidate . vars)) . candidates)
|
(((and head (candidate . vars)) . candidates)
|
||||||
(cond
|
(cond
|
||||||
((not (intset-ref avail candidate))
|
((not (intset-ref avail candidate))
|
||||||
|
@ -331,13 +333,14 @@ false. It could be that both true and false proofs are available."
|
||||||
;; Yay, a match. Mark expression as equivalent. If
|
;; Yay, a match. Mark expression as equivalent. If
|
||||||
;; we provide the definitions for the successor, mark
|
;; we provide the definitions for the successor, mark
|
||||||
;; the vars for substitution.
|
;; the vars for substitution.
|
||||||
(finish (intmap-add equiv-labels label head)
|
|
||||||
(let ((defs (term-defs term)))
|
(let ((defs (term-defs term)))
|
||||||
|
(finish (intmap-add equiv-labels label head)
|
||||||
(if defs
|
(if defs
|
||||||
(fold (lambda (def var var-substs)
|
(fold (lambda (def var var-substs)
|
||||||
(intmap-add var-substs def var))
|
(intmap-add var-substs def var))
|
||||||
var-substs defs vars)
|
var-substs defs vars)
|
||||||
var-substs))))))))))))
|
var-substs)
|
||||||
|
defs)))))))))))
|
||||||
(_ (values equiv-labels var-substs))))
|
(_ (values equiv-labels var-substs))))
|
||||||
|
|
||||||
;; Traverse the labels in fun in reverse post-order, which will
|
;; Traverse the labels in fun in reverse post-order, which will
|
||||||
|
|
|
@ -300,3 +300,40 @@
|
||||||
(cons 't (if x 't 'f))
|
(cons 't (if x 't 'f))
|
||||||
(cons 'f (if x 't 'f)))))
|
(cons 'f (if x 't 'f)))))
|
||||||
'(3 #t #f #nil ()))))
|
'(3 #t #f #nil ()))))
|
||||||
|
|
||||||
|
(with-test-prefix "cse auxiliary definitions"
|
||||||
|
(define test-code
|
||||||
|
'(begin
|
||||||
|
(define count 1)
|
||||||
|
(set! count count) ;; Avoid inlining
|
||||||
|
|
||||||
|
(define (main)
|
||||||
|
(define (trampoline thunk)
|
||||||
|
(let loop ((i 0) (result #f))
|
||||||
|
(cond
|
||||||
|
((< i 1)
|
||||||
|
(loop (+ i 1) (thunk)))
|
||||||
|
(else
|
||||||
|
(unless (= result 42) (error "bad result" result))
|
||||||
|
(newline)
|
||||||
|
result))))
|
||||||
|
(define (test n)
|
||||||
|
(let ((matrix (make-vector n)))
|
||||||
|
(let loop ((i (- n 1)))
|
||||||
|
(when (>= i 0)
|
||||||
|
(vector-set! matrix i (make-vector n 42))
|
||||||
|
(loop (- i 1))))
|
||||||
|
(vector-ref (vector-ref matrix 0) 0)))
|
||||||
|
|
||||||
|
(trampoline (lambda () (test count))))
|
||||||
|
main))
|
||||||
|
|
||||||
|
(define test-proc #f)
|
||||||
|
(pass-if "compiling test works"
|
||||||
|
(begin
|
||||||
|
(set! test-proc (compile test-code))
|
||||||
|
(procedure? test-proc)))
|
||||||
|
|
||||||
|
(pass-if-equal "test terminates without error" 42
|
||||||
|
(test-proc)))
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue