1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-01 04:10:18 +02:00
guile/test-suite/tests/cse.test
Andy Wingo 0dd7c54075 Merge remote-tracking branch 'origin/stable-2.0'
Conflicts:
	libguile/deprecated.c
	libguile/ports.c
	libguile/ports.h
	libguile/strports.c
	test-suite/tests/cse.test
2012-06-22 13:18:02 +02:00

284 lines
9 KiB
Scheme
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;;; tree-il.test --- test suite for compiling tree-il -*- scheme -*-
;;;; Andy Wingo <wingo@pobox.com> --- May 2009
;;;;
;;;; Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
;;;;
;;;; This library is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Lesser General Public
;;;; License as published by the Free Software Foundation; either
;;;; version 3 of the License, or (at your option) any later version.
;;;;
;;;; This library is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;;; Lesser General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU Lesser General Public
;;;; License along with this library; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
(define-module (test-suite tree-il)
#:use-module (test-suite lib)
#:use-module (system base compile)
#:use-module (system base pmatch)
#:use-module (system base message)
#:use-module (language tree-il)
#:use-module (language tree-il canonicalize)
#:use-module (language tree-il primitives)
#:use-module (language tree-il fix-letrec)
#:use-module (language tree-il cse)
#:use-module (language tree-il peval)
#:use-module (language glil)
#:use-module (srfi srfi-13))
(define-syntax pass-if-cse
(syntax-rules ()
((_ in pat)
(pass-if 'in
(let ((evaled (unparse-tree-il
(canonicalize!
(fix-letrec!
(cse
(peval
(expand-primitives!
(resolve-primitives!
(compile 'in #:from 'scheme #:to 'tree-il)
(current-module))))))))))
(pmatch evaled
(pat #t)
(_ (pk 'cse-mismatch)
((@ (ice-9 pretty-print) pretty-print)
'in)
(newline)
((@ (ice-9 pretty-print) pretty-print)
evaled)
(newline)
((@ (ice-9 pretty-print) pretty-print)
'pat)
(newline)
#f)))))))
(with-test-prefix "cse"
;; The eq? propagates, and (if TEST #t #f) folds to TEST if TEST is
;; boolean-valued.
(pass-if-cse
(lambda (x y)
(and (eq? x y)
(eq? x y)))
(lambda _
(lambda-case
(((x y) #f #f #f () (_ _))
(primcall eq? (lexical x _) (lexical y _))))))
;; The eq? propagates, and (if TEST #f #t) folds to (not TEST).
(pass-if-cse
(lambda (x y)
(if (eq? x y) #f #t))
(lambda _
(lambda-case
(((x y) #f #f #f () (_ _))
(primcall not
(primcall eq? (lexical x _) (lexical y _)))))))
;; (if TEST (not TEST) #f)
;; => (if TEST #f #f)
;; => (begin TEST #f)
;; => #f
(pass-if-cse
(lambda (x y)
(and (eq? x y) (not (eq? x y))))
(lambda _
(lambda-case
(((x y) #f #f #f () (_ _))
(const #f)))))
;; (if TEST #f TEST) => (if TEST #f #f) => ...
(pass-if-cse
(lambda (x y)
(if (eq? x y) #f (eq? x y)))
(lambda _
(lambda-case
(((x y) #f #f #f () (_ _))
(const #f)))))
;; The same, but side-effecting primitives do not propagate.
(pass-if-cse
(lambda (x y)
(and (set-car! x y) (not (set-car! x y))))
(lambda _
(lambda-case
(((x y) #f #f #f () (_ _))
(if (primcall set-car!
(lexical x _)
(lexical y _))
(primcall not
(primcall set-car!
(lexical x _)
(lexical y _)))
(const #f))))))
;; Primitives that access mutable memory can propagate, as long as
;; there is no intervening mutation.
(pass-if-cse
(lambda (x y)
(and (string-ref x y)
(begin
(string-ref x y)
(not (string-ref x y)))))
(lambda _
(lambda-case
(((x y) #f #f #f () (_ _))
(seq (primcall string-ref
(lexical x _)
(lexical y _))
(const #f))))))
;; However, expressions with dependencies on effects do not propagate
;; through a lambda.
(pass-if-cse
(lambda (x y)
(and (string-ref x y)
(lambda ()
(and (string-ref x y) #t))))
(lambda _
(lambda-case
(((x y) #f #f #f () (_ _))
(if (primcall string-ref
(lexical x _)
(lexical y _))
(lambda _
(lambda-case
((() #f #f #f () ())
(if (primcall string-ref
(lexical x _)
(lexical y _))
(const #t)
(const #f)))))
(const #f))))))
;; A mutation stops the propagation.
(pass-if-cse
(lambda (x y)
(and (string-ref x y)
(begin
(string-set! x #\!)
(not (string-ref x y)))))
(lambda _
(lambda-case
(((x y) #f #f #f () (_ _))
(if (primcall string-ref
(lexical x _)
(lexical y _))
(seq (primcall string-set!
(lexical x _)
(const #\!))
(primcall not
(primcall string-ref
(lexical x _)
(lexical y _))))
(const #f))))))
;; Predicates are only added to the database if they are in a
;; predicate context.
(pass-if-cse
(lambda (x y)
(begin (eq? x y) (eq? x y)))
(lambda _
(lambda-case
(((x y) #f #f #f () (_ _))
(primcall eq? (lexical x _) (lexical y _))))))
;; Conditional bailouts do cause primitives to be added to the DB.
(pass-if-cse
(lambda (x y)
(begin (unless (eq? x y) (throw 'foo)) (eq? x y)))
(lambda _
(lambda-case
(((x y) #f #f #f () (_ _))
(seq (if (primcall eq?
(lexical x _) (lexical y _))
(void)
(primcall throw (const foo)))
(const #t))))))
;; A chain of tests in a conditional bailout add data to the DB
;; correctly.
(pass-if-cse
(lambda (x y)
(begin
(unless (and (struct? x) (eq? (struct-vtable x) x-vtable))
(throw 'foo))
(if (and (struct? x) (eq? (struct-vtable x) x-vtable))
(struct-ref x y)
(throw 'bar))))
(lambda _
(lambda-case
(((x y) #f #f #f () (_ _))
(seq
(fix (failure) (_)
((lambda _
(lambda-case
((() #f #f #f () ())
(primcall throw (const foo))))))
(if (primcall struct? (lexical x _))
(if (primcall eq?
(primcall struct-vtable (lexical x _))
(toplevel x-vtable))
(void)
(call (lexical failure _)))
(call (lexical failure _))))
(primcall struct-ref (lexical x _) (lexical y _)))))))
;; Strict argument evaluation also adds info to the DB.
(pass-if-cse
(lambda (x)
((lambda (z)
(+ z (if (and (struct? x) (eq? (struct-vtable x) x-vtable))
(struct-ref x 2)
(throw 'bar))))
(if (and (struct? x) (eq? (struct-vtable x) x-vtable))
(struct-ref x 1)
(throw 'foo))))
(lambda _
(lambda-case
(((x) #f #f #f () (_))
(let (z) (_)
((fix (failure) (_)
((lambda _
(lambda-case
((() #f #f #f () ())
(primcall throw (const foo))))))
(if (primcall struct? (lexical x _))
(if (primcall eq?
(primcall struct-vtable (lexical x _))
(toplevel x-vtable))
(primcall struct-ref (lexical x _) (const 1))
(call (lexical failure _)))
(call (lexical failure _)))))
(primcall + (lexical z _)
(primcall struct-ref (lexical x _) (const 2))))))))
;; Replacing named expressions with lexicals.
(pass-if-cse
(let ((x (car y)))
(cons x (car y)))
(let (x) (_) ((primcall car (toplevel y)))
(primcall cons (lexical x _) (lexical x _))))
;; Dominating expressions only provide predicates when evaluated in
;; test context.
(pass-if-cse
(let ((t (car x)))
(if (car x)
'one
'two))
;; Actually this one should reduce in other ways, but this is the
;; current reduction:
(seq
(primcall car (toplevel x))
(if (primcall car (toplevel x))
(const one)
(const two)))))