[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Guile-commits] 02/03: Allow functions to mark themselves as maybe-unuse
From: |
Andy Wingo |
Subject: |
[Guile-commits] 02/03: Allow functions to mark themselves as maybe-unused |
Date: |
Thu, 24 Aug 2023 05:51:06 -0400 (EDT) |
wingo pushed a commit to branch main
in repository guile.
commit 1f70d597dbc38585f0eeb6f5d8ca4ae62ed6ec3a
Author: Andy Wingo <wingo@pobox.com>
AuthorDate: Thu Aug 24 11:36:10 2023 +0200
Allow functions to mark themselves as maybe-unused
* module/language/tree-il/analyze.scm (<reference-graph>): Oh my
goodness, constructor args were reversed relative to field order.
Constructor use was consistent but it was terribly confusing; fixed and
updated uses.
(unused-toplevel-analysis): Add ability for functions to mark themselves
as "maybe-unused"; such functions won't cause unused toplevel warnings.
* module/language/tree-il/compile-bytecode.scm (sanitize-meta):
(compile-closure):
* module/language/tree-il/compile-cps.scm (sanitize-meta): Prevent
maybe-unused from being needlessly written out to the binary.
---
module/language/tree-il/analyze.scm | 84 ++++++++++++++++++----------
module/language/tree-il/compile-bytecode.scm | 11 +++-
module/language/tree-il/compile-cps.scm | 2 +-
3 files changed, 66 insertions(+), 31 deletions(-)
diff --git a/module/language/tree-il/analyze.scm
b/module/language/tree-il/analyze.scm
index c949b5f54..e9a803919 100644
--- a/module/language/tree-il/analyze.scm
+++ b/module/language/tree-il/analyze.scm
@@ -194,7 +194,7 @@ given `tree-il' element."
;; definition we're currently in). The second part (`refs' below) is
;; effectively a graph from which we can determine unused top-level
definitions.
(define-record-type <reference-graph>
- (make-reference-graph refs defs toplevel-context)
+ (make-reference-graph defs refs toplevel-context)
reference-graph?
(defs reference-graph-defs) ;; ((NAME . LOC) ...)
(refs reference-graph-refs) ;; ((REF-CONTEXT REF ...) ...)
@@ -257,46 +257,66 @@ given `tree-il' element."
(define unused-toplevel-analysis
;; Report unused top-level definitions that are not exported.
- (let ((add-ref-from-context
- (lambda (graph name)
- ;; Add an edge CTX -> NAME in GRAPH.
- (let* ((refs (reference-graph-refs graph))
- (defs (reference-graph-defs graph))
- (ctx (reference-graph-toplevel-context graph))
- (ctx-refs (or (and=> (vhash-assq ctx refs) cdr) '())))
- (make-reference-graph (vhash-consq ctx (cons name ctx-refs) refs)
- defs ctx)))))
+ (let ()
+ (define initial-graph
+ (make-reference-graph vlist-null vlist-null #f))
+
+ (define (add-def graph name src)
+ (match graph
+ (($ <reference-graph> defs refs ctx)
+ (make-reference-graph (vhash-consq name src defs) refs name))))
+
+ (define (add-ref graph pred succ)
+ ;; Add a ref edge PRED -> SUCC in GRAPH.
+ (match graph
+ (($ <reference-graph> defs refs ctx)
+ (let* ((succs (match (vhash-assq pred refs)
+ ((pred . succs) succs)
+ (#f '())))
+ (refs (vhash-consq pred (cons succ succs) refs)))
+ (make-reference-graph defs refs ctx)))))
+
+ (define (add-ref-from-context graph name)
+ ;; Add a ref edge from the current context to NAME in GRAPH.
+ (add-ref graph (reference-graph-toplevel-context graph) name))
+
+ (define (add-root-ref graph name)
+ ;; Add a ref edge to NAME from the root, because its metadata is
+ ;; marked maybe-unused.
+ (add-ref graph #f name))
+
(define (macro-variable? name env)
(and (module? env)
(let ((var (module-variable env name)))
(and var (variable-bound? var)
(macro? (variable-ref var))))))
+ (define (maybe-unused? metadata)
+ (assq 'maybe-unused metadata))
+
(make-tree-analysis
(lambda (x graph env locs)
;; Going down into X.
- (let ((ctx (reference-graph-toplevel-context graph))
- (refs (reference-graph-refs graph))
- (defs (reference-graph-defs graph)))
- (match x
- (($ <toplevel-ref> src mod name)
- (add-ref-from-context graph name))
- (($ <toplevel-define> src mod name expr)
- (let ((refs refs)
- (defs (vhash-consq name (or src (find pair? locs))
- defs)))
- (make-reference-graph refs defs name)))
- (($ <toplevel-set> src mod name expr)
- (add-ref-from-context graph name))
- (_ graph))))
+ (match x
+ (($ <toplevel-ref> src mod name)
+ (add-ref-from-context graph name))
+ (($ <toplevel-define> src mod name expr)
+ (let ((graph (add-def graph name (or src (find pair? locs)))))
+ (match expr
+ (($ <lambda> src (? maybe-unused?) body)
+ (add-root-ref graph name))
+ (_ graph))))
+ (($ <toplevel-set> src mod name expr)
+ (add-ref-from-context graph name))
+ (_ graph)))
(lambda (x graph env locs)
;; Leaving X's scope.
(match x
(($ <toplevel-define>)
- (let ((refs (reference-graph-refs graph))
- (defs (reference-graph-defs graph)))
- (make-reference-graph refs defs #f)))
+ (match graph
+ (($ <reference-graph> defs refs ctx)
+ (make-reference-graph defs refs #f))))
(_ graph)))
(lambda (graph env)
@@ -308,9 +328,15 @@ given `tree-il' element."
;; private bindings. FIXME: The `make-syntax-transformer' calls don't
;; contain any literal `toplevel-ref' of the global bindings they use so
;; this strategy fails.
+ (define exports (make-hash-table))
+ (when (module? env)
+ (module-for-each (lambda (name var) (hashq-set! exports var name))
+ (module-public-interface env)))
(define (exported? name)
(if (module? env)
- (module-variable (module-public-interface env) name)
+ (and=> (module-variable env name)
+ (lambda (var)
+ (hashq-ref exports var)))
#t))
(let-values (((public-defs private-defs)
@@ -332,7 +358,7 @@ given `tree-il' element."
(warning 'unused-toplevel loc name))))
unused))))
- (make-reference-graph vlist-null vlist-null #f))))
+ initial-graph)))
;;;
diff --git a/module/language/tree-il/compile-bytecode.scm
b/module/language/tree-il/compile-bytecode.scm
index 71f22dde7..c4c9bf614 100644
--- a/module/language/tree-il/compile-bytecode.scm
+++ b/module/language/tree-il/compile-bytecode.scm
@@ -724,6 +724,15 @@ in the frame with for the lambda-case clause @var{clause}."
(visit body)) ; Body.
temporary-count)))) ; Temporaries.
+(define (sanitize-meta meta)
+ (match meta
+ (() '())
+ (((k . v) . meta)
+ (let ((meta (sanitize-meta meta)))
+ (case k
+ ((maybe-unused) meta)
+ (else (acons k v meta)))))))
+
(define (compile-closure asm closure assigned? lookup-closure)
(define-record-type <env>
(make-env prev name id idx closure? boxed? next-local)
@@ -1375,7 +1384,7 @@ in the frame with for the lambda-case clause
@var{clause}."
(match closure
(($ <closure> label ($ <lambda> src meta body) module-scope free)
(when src (emit-source asm src))
- (emit-begin-program asm label meta)
+ (emit-begin-program asm label (sanitize-meta meta))
(emit-clause #f body module-scope free)
(emit-end-program asm))))
diff --git a/module/language/tree-il/compile-cps.scm
b/module/language/tree-il/compile-cps.scm
index ae5df10ed..ff22fa5ca 100644
--- a/module/language/tree-il/compile-cps.scm
+++ b/module/language/tree-il/compile-cps.scm
@@ -1315,7 +1315,7 @@ use as the proc slot."
(((k . v) . meta)
(let ((meta (sanitize-meta meta)))
(case k
- ((arg-representations noreturn return-type) meta)
+ ((arg-representations noreturn return-type maybe-unused) meta)
(else (acons k v meta)))))))
;;; The conversion from Tree-IL to CPS essentially wraps every