Skip to content

Commit e5555b7

Browse files
authored
Fix non-total predicates in tail position in cptypes (#985)
Avoid moving predicates from tail position when they may raise an error, in spite the result in known in case of a success.
1 parent e809494 commit e5555b7

File tree

3 files changed

+53
-14
lines changed

3 files changed

+53
-14
lines changed

mats/cptypes.ms

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,25 @@
903903
(loop (cdr p?*))))))
904904
(loop (cdr f*)))))))
905905
906+
(mat cptypes-predicates
907+
; don't remove (exact? x) from tail position if it may raise an error
908+
(parameterize ([debug-level 2])
909+
(not
910+
(cptypes-equivalent-expansion?
911+
'(lambda (x) (when (or (fixnum? x) (list? x)) (#2%exact? x)))
912+
'(lambda (x) (when (or (fixnum? x) (list? x)) (#2%exact? x) #t)))))
913+
(parameterize ([debug-level 2])
914+
(cptypes-equivalent-expansion?
915+
'(lambda (x) (when (or (fixnum? x) (list? x)) (#3%exact? x)))
916+
'(lambda (x) (when (or (fixnum? x) (list? x)) (#3%exact? x) #t))))
917+
(cptypes-equivalent-expansion?
918+
'(lambda (x) (when (or (fixnum? x) (list? x)) (list (exact? x))))
919+
'(lambda (x) (when (or (fixnum? x) (list? x)) (list (begin (exact? x) #t)))))
920+
(cptypes-equivalent-expansion?
921+
'(lambda (x) (when (or (fixnum? x) (list? x)) (if (exact? x) 1 2)))
922+
'(lambda (x) (when (or (fixnum? x) (list? x)) (exact? x) 1)))
923+
)
924+
906925
(mat cptypes-unsafe
907926
(cptypes-equivalent-expansion?
908927
'(lambda (x) (when (pair? x) (car x)))

release_notes/release_notes.stex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ The compiler now inlines more numeric predicates, in particular \scheme{real?},
137137
The type recovery pass has improved support for \scheme{cfl+} and similar functions,
138138
\scheme{integer?}, \scheme{zero?}, and similar predicates, and \scheme{+} and \scheme{-}.
139139

140+
Avoid moving predicates from tail position when they may raise
141+
an error, in spite the result in known in case of a success.
142+
140143
\subsection{Unicode 16.0.0 support (10.3.0)}
141144

142145
The character sets, character classes, and word-breaking algorithms for character, string,

s/cptypes.ss

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Notes:
1919
- (cptypes ir ctxt types) -> (values ir ret types t-types f-types)
2020
+ arguments
2121
ir: expression to be optimized
22-
ctxt: 'effect 'test 'value
22+
ctxt: 'effect 'test 'value 'tail
2323
types: an immutable dictionary (currently an intmap).
2424
The dictionary connects the counter of a prelex with the types
2525
discovered previously.
@@ -753,10 +753,10 @@ Notes:
753753
;; here because we know an error will be raised); we need to keep
754754
;; those non-tail:
755755
(single-valued? e))
756-
;; A 'test or 'effect context cannot have an active attachment,
756+
;; A 'test, 'effect or 'value context cannot have an active attachment,
757757
;; and they are non-tail with respect to the enclosing function,
758758
;; so ok to have `e` immediately:
759-
(not (eq? 'value ctxt)))
759+
(not (eq? 'tail ctxt)))
760760
;; => It's ok to potentially move `e` into tail position
761761
;; from a continuation-marks perspective. Although an
762762
;; error may trigger a handler that has continuation-mark
@@ -1478,8 +1478,8 @@ Notes:
14781478
types2 t-types2 f-types2))])))
14791479

14801480
(define-specialize/unrestricted 2 $call-setting-continuation-attachment
1481-
;; body is in 'value context, because called with a mark
1482-
[(e1 e2) (handle-call-attachment preinfo pr e1 e2 ctxt oldtypes plxc 'value)])
1481+
;; body is in 'tail context, because called with a mark
1482+
[(e1 e2) (handle-call-attachment preinfo pr e1 e2 ctxt oldtypes plxc 'tail)])
14831483

14841484
(define-specialize/unrestricted 2 $call-getting-continuation-attachment
14851485
[(e1 e2) (handle-call-attachment preinfo pr e1 e2 ctxt oldtypes plxc ctxt)])
@@ -1607,6 +1607,25 @@ Notes:
16071607
[r* (if unsafe nr* r*)])
16081608
(fold-primref/try-predicate preinfo pr e* ret r* ctxt ntypes oldtypes plxc))]))))
16091609

1610+
(define (wrap/result ctxt ir qret ntypes)
1611+
; Assume cret is a quoted constant, that can be used as result in the expression
1612+
; and also as the the predicate in ret.
1613+
(let ([ir (cond
1614+
[(eq? ctxt 'effect)
1615+
ir]
1616+
[(and (eq? ctxt 'tail)
1617+
(>= (debug-level) 2)
1618+
(nanopass-case (Lsrc Expr) ir
1619+
[(call ,preinfo ,pr ,e* ...)
1620+
(let ([flags (primref-flags pr)])
1621+
(and (not (all-set? (prim-mask unsafe) flags))
1622+
(not (all-set? (prim-mask unrestricted) flags))))]
1623+
[else #t]))
1624+
ir]
1625+
[else
1626+
(make-seq ctxt ir qret)])])
1627+
(values ir qret ntypes #f #f)))
1628+
16101629
(define (fold-primref/try-predicate preinfo pr e* ret r* ctxt ntypes oldtypes plxc)
16111630
(cond
16121631
[(not (and (fx= (length e*) 1) (primref->predicate pr #t)))
@@ -1617,11 +1636,9 @@ Notes:
16171636
(primref->argument-predicate pr 0 1 #t))])
16181637
(cond
16191638
[(predicate-implies? r (primref->predicate pr #f))
1620-
(values (make-seq ctxt `(call ,preinfo ,pr ,e) true-rec)
1621-
true-rec ntypes #f #f)]
1639+
(wrap/result ctxt `(call ,preinfo ,pr ,e) true-rec ntypes)]
16221640
[(predicate-disjoint? r (primref->predicate pr #t))
1623-
(values (make-seq ctxt `(call ,preinfo ,pr ,e) false-rec)
1624-
false-rec ntypes #f #f)]
1641+
(wrap/result ctxt `(call ,preinfo ,pr ,e) false-rec ntypes)]
16251642
[else
16261643
(let ([ttypes (and (eq? ctxt 'test)
16271644
(pred-env-add/ref ntypes e (primref->predicate pr #t) plxc))]
@@ -1717,7 +1734,7 @@ Notes:
17171734
(let*-values ([(ntypes e* r* t* t-t* f-t*)
17181735
(map-Expr/delayed e* oldtypes plxc)]
17191736
[(e0 ret0 types0 t-types0 f-types0 e0-bottom?)
1720-
(Expr/call e0 'value ntypes oldtypes plxc)])
1737+
(Expr/call e0 'tail ntypes oldtypes plxc)])
17211738
(cond
17221739
[(or (and e0-bottom? e0)
17231740
(ormap (lambda (e r) (and (predicate-implies? r 'bottom) e)) e* r*))
@@ -1926,7 +1943,7 @@ Notes:
19261943
(values (if (unsafe-unreachable? e2)
19271944
(make-seq ctxt e1 e3)
19281945
(if (or (< (debug-level) 2)
1929-
(not (eq? ctxt 'value)))
1946+
(not (eq? ctxt 'tail)))
19301947
(make-seq ctxt `(if ,e1 ,e2 ,void-rec) e3)
19311948
;; If `debug-level` >= 2, may need to keep in tail position
19321949
ir))
@@ -1935,7 +1952,7 @@ Notes:
19351952
(values (if (unsafe-unreachable? e3)
19361953
(make-seq ctxt e1 e2)
19371954
(if (or (< (debug-level) 2)
1938-
(not (eq? ctxt 'value)))
1955+
(not (eq? ctxt 'tail)))
19391956
(make-seq ctxt `(if ,e1 ,void-rec ,e3) e2)
19401957
;; As above:
19411958
ir))
@@ -1986,7 +2003,7 @@ Notes:
19862003
(nanopass-case (Lsrc CaseLambdaClause) cl
19872004
[(clause (,x* ...) ,interface ,body)
19882005
(let-values ([(body ret types t-types f-types)
1989-
(Expr body 'value types plxc)])
2006+
(Expr body 'tail types plxc)]) ;use 'tail context just in case
19902007
(for-each (lambda (x) (prelex-operand-set! x #f)) x*)
19912008
(with-output-language (Lsrc CaseLambdaClause)
19922009
`(clause (,x* ...) ,interface ,body)))]))
@@ -2107,7 +2124,7 @@ Notes:
21072124
; external version of cptypes: Lsrc -> Lsrc
21082125
(define (Scptypes ir)
21092126
(let-values ([(ir ret types t-types f-types)
2110-
(Expr ir 'value pred-env-empty (box 0))])
2127+
(Expr ir 'tail pred-env-empty (box 0))])
21112128
ir))
21122129

21132130
(set! $cptypes Scptypes)

0 commit comments

Comments
 (0)