Issue #248 - Ensure unique lambda ID's/args

During a beta expansion, renumber lambda ID's and rename lambda args if necessary so that we do not introduce duplicates. Dupes are a problem as they throw of the analysis DB and can lead to the optimizer inserting the wrong values when code is optimized-out.
This commit is contained in:
Justin Ethier 2018-03-24 19:23:30 -04:00
parent 282fb0793c
commit ebc68e6746

View file

@ -683,7 +683,7 @@
((app? exp) ((app? exp)
;; Beta expansion of functions only called once, from CWC ;; Beta expansion of functions only called once, from CWC
(if (beta-expand/called-once? exp) (if (beta-expand/called-once? exp)
(set! exp (beta-expand-app exp))) (set! exp (beta-expand-app exp #f)))
;; END ;; END
(let* ((fnc (opt:contract (car exp)))) (let* ((fnc (opt:contract (car exp))))
@ -1337,7 +1337,7 @@
(return #f)))) (return #f))))
;; Check app and beta expand if possible, else just return given code ;; Check app and beta expand if possible, else just return given code
(define (beta-expand-app exp) (define (beta-expand-app exp rename-lambdas)
(let* ((args (cdr exp)) (let* ((args (cdr exp))
(var (adb:get/default (car exp) #f)) (var (adb:get/default (car exp) #f))
;; Function definition, or #f if none ;; Function definition, or #f if none
@ -1366,34 +1366,56 @@
(list? formals) (list? formals)
(= (length args) (length formals))) (= (length args) (length formals)))
;(trace:error `(JAE DEBUG beta expand ,exp)) ;(trace:error `(JAE DEBUG beta expand ,exp))
(beta-expansion-app exp fnc) ; exp (beta-expansion-app exp fnc rename-lambdas) ; exp
) )
(else exp)))) ;; beta expansion failed (else exp)))) ;; beta expansion failed
;; Replace function call with body of fnc ;; Replace function call with body of fnc
(define (beta-expansion-app exp fnc) (define (beta-expansion-app exp fnc rename-lambdas)
;; Mapping from a formal => actual arg ;; Mapping from a formal => actual arg
(define formals/actuals (define formals/actuals
(map cons (ast:lambda-args fnc) (cdr exp))) (map cons (ast:lambda-args fnc) (cdr exp)))
(define (replace ref) (define (replace ref renamed)
(let ((r (assoc ref formals/actuals))) (let ((r (assoc ref formals/actuals)))
(if r (cdr r) ref))) (if r
(define (scan exp) (scan (cdr r) renamed)
;ref
(let ((rn (assoc ref renamed)))
(if rn
(cdr rn)
ref)))))
(define (scan exp renamed)
(cond (cond
((ast:lambda? exp) ((ast:lambda? exp)
(ast:%make-lambda (if rename-lambdas
(ast:lambda-id exp) (let* ((args (ast:lambda-formals->list exp))
(ast:lambda-args exp) (ltype (ast:lambda-formals-type exp))
(scan (ast:lambda-body exp)) (a-lookup (map (lambda (a) (cons a (gensym a))) args)))
(ast:lambda-has-cont exp))) (ast:%make-lambda
;; if rename-lambdas also need to rename lambda formals here and
;; setup and a-lookup to replace any refs with the renamed formal. the
;; problem is, if we don't do this, there will be multiple lambda's with
;; the same arg, which causes problems when the optimizer tries to replace
;; one with its value, since different instances will have different values
(ast:get-next-lambda-id!)
(list->lambda-formals
(map (lambda (p) (cdr p)) a-lookup)
ltype)
(scan (ast:lambda-body exp) (append a-lookup renamed))
(ast:lambda-has-cont exp)))
(ast:%make-lambda
(ast:lambda-id exp)
(ast:lambda-args exp)
(scan (ast:lambda-body exp) renamed)
(ast:lambda-has-cont exp))))
((ref? exp) ((ref? exp)
(replace exp)) (replace exp renamed))
((quote? exp) ((quote? exp)
exp) exp)
((app? exp) ((app? exp)
(map scan exp)) (map (lambda (e) (scan e renamed)) exp))
(else exp))) (else exp)))
(scan (car (ast:lambda-body fnc)))) (scan (car (ast:lambda-body fnc)) '()))
;; Full beta expansion phase, make a pass over all of the program's AST ;; Full beta expansion phase, make a pass over all of the program's AST
(define (opt:beta-expand exp) (define (opt:beta-expand exp)
@ -1420,7 +1442,7 @@
,(opt:beta-expand (if->else exp)))) ,(opt:beta-expand (if->else exp))))
((app? exp) ((app? exp)
(let ((code (if (beta-expand? exp) (let ((code (if (beta-expand? exp)
(beta-expand-app exp) (beta-expand-app exp #t)
exp))) exp)))
(map opt:beta-expand code))) (map opt:beta-expand code)))
(else exp))) (else exp)))