⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 optimizer.scm

📁 Scheme跨平台编译器
💻 SCM
📖 第 1 页 / 共 5 页
字号:
					     (walk-generic n class params subs)					     (begin					       (debugging 'o "consed rest parameter at call site" var n)					       (let-values ([(args rargs) (split-at args n)])						 (let ([n2 (make-node							    '##core#call							    params							    (map walk								 (cons fun								       (append 									args									(list									 (if (null? rargs)									     (qnode '())									     (make-node									      '##core#inline_allocate 									      (list "C_a_i_list" (* 3 (length rargs)))									      rargs) ) ) ) ) ) ) ] )						   (set! rest-consers (cons n2 rest-consers))						   n2) ) ) ) ) ]				      [else (walk-generic n class params subs)] ) ) ) ) ) ]			[else (walk-generic n class params subs)] ) ) ]	       [(##core#lambda)		(if (first params)		    (walk-generic n class params subs)		    (make-node '##core#call (cons #t (cdr params)) (map walk subs)) ) ]	       [else (walk-generic n class params subs)] ) ) )	  ((set!)	   (let ([var (first params)])	     (cond [(or (test var 'contractable) (test var 'replacable))		    (touch)		    (make-node '##core#undefined '() '()) ]		   [(and (or (not (test var 'global))			     block-compilation			     (and export-list (not (memq var export-list))) )			 (not (test var 'references)) 			 (not (expression-has-side-effects? (first subs) db)) )		    (touch)		    (debugging 'o "removed side-effect free assignment to unused variable" var)		    (make-node '##core#undefined '() '()) ]		   [else (make-node 'set! params (list (walk (car subs))))] ) ) )	  (else (walk-generic n class params subs)) ) ) )        (define (walk-generic n class params subs)      (let ((subs2 (map walk subs)))	(if (every eq? subs subs2)	    n	    (make-node class params subs2) ) ) )    (if (perform-pre-optimization! node db)	(values node #t)	(begin	  (debugging 'p "traversal phase...")	  (set! simplified-ops '())	  (let ((node2 (walk node)))	    (when (pair? simplified-classes) (debugging 'o "simplifications" simplified-classes))	    (when (and (pair? simplified-ops) (debugging 'o "  call simplifications:"))	      (for-each	       (lambda (p)		 (print* #\tab (car p))		 (if (> (cdr p) 1)		     (print #\tab (cdr p))		     (newline) ) )	       simplified-ops) )	    (when (> replaced-vars 0) (debugging 'o "replaced variables" replaced-vars))	    (when (> removed-lets 0) (debugging 'o "removed binding forms" removed-lets))	    (when (> removed-ifs 0) (debugging 'o "removed conditional forms" removed-ifs))	    (values node2 dirty) ) ) ) ) );;; Pre-optimization phase:;; - Transform expressions of the form '(if (not <x>) <y> <z>)' into '(if <x> <z> <y>)'.; - Transform expressions of the form '(if (<x> <y> ...) <z> <q>)' into '<z>' if <x> names a;   standard-binding that is never #f and if it's arguments are free of side-effects.(define (perform-pre-optimization! node db)  (let ((dirty #f)	(removed-nots 0) )    (define (touch) (set! dirty #t) #t)    (define (test sym prop) (get db sym prop))    (debugging 'p "pre-optimization phase...")    ;; Handle '(if (not ...) ...)':    (if (test 'not 'standard-binding)	(for-each 	 (lambda (site)	   (let* ((n (cdr site))		  (subs (node-subexpressions n))		  (kont (first (node-parameters (second subs))))		  (lnode (and (not (test kont 'unknown)) (test kont 'value)))		  (krefs (test kont 'references)) )	     ;; Call-site has one argument and a known continuation (which is a ##core#lambda)	     ;;  that has only one use:	     (if (and lnode krefs (= 1 (length krefs)) (= 3 (length subs))		      (eq? '##core#lambda (node-class lnode)) )		 (let* ((llist (third (node-parameters lnode)))			(body (first (node-subexpressions lnode))) 			(bodysubs (node-subexpressions body)) )		   ;; Continuation has one parameter?		   (if (and (proper-list? llist) (null? (cdr llist)))		       (let* ((var (car llist))			      (refs (test var 'references)) )			 ;; Parameter is only used once?			 (if (and refs (= 1 (length refs)) (eq? 'if (node-class body)))			     ;; Continuation contains an 'if' node?			     (let ((iftest (first (node-subexpressions body))))			       ;; Parameter is used only once and is the test-argument?			       (if (and (eq? '##core#variable (node-class iftest))					(eq? var (first (node-parameters iftest))) )				   ;; Modify call-site to call continuation directly and swap branches				   ;;  in the conditional:				   (begin				     (set! removed-nots (+ removed-nots 1))				     (node-parameters-set! n '(#t))				     (node-subexpressions-set! n (cdr subs))				     (node-subexpressions-set! 				      body				      (cons (car bodysubs) (reverse (cdr bodysubs))) )				     (touch) ) ) ) ) ) ) ) ) ) )	 (or (test 'not 'call-sites) '()) ) )        ;; Handle '(if (<func> <a> ...) ...)', where <func> never returns false:    (for-each     (lambda (varname)       (if (test varname 'standard-binding)	   (for-each	    (lambda (site)	      (let* ((n (cdr site))		     (subs (node-subexpressions n))		     (kont (first (node-parameters (second subs)))) 		     (krefs (test kont 'references)) 		     (lnode (and (not (test kont 'unknown)) (test kont 'value))) )		;; Call-site has side-effect-free arguments and a known continuation that has only one use?		(if (and lnode			 (eq? '##core#lambda (node-class lnode))			 krefs (= 1 (length krefs))			 (not (any (lambda (sn) (expression-has-side-effects? sn db)) (cddr subs))) )		    (let* ((llist (third (node-parameters lnode)))			   (body (first (node-subexpressions lnode))) )		      ;; Continuation has one parameter and contains an 'if' node?		      (if (and (proper-list? llist)			       (null? (cdr llist))			       (eq? 'if (node-class body)) )			  (let* ((var (car llist))				 (refs (test var 'references)) 				 (iftest (first (node-subexpressions body))) )			    ;; Parameter is used only once and is the test-argument?			    (if (and refs (= 1 (length refs))				     (eq? '##core#variable (node-class iftest))				     (eq? var (first (node-parameters iftest))) )				(let ((bodysubs (node-subexpressions body)))				  ;; Modify call-site to call continuation directly and swap branches				  ;;  in the conditional:				  (debugging 'o "removed call in test-context" varname)				  (node-parameters-set! n '(#t))				  (node-subexpressions-set! n (list (second subs) (qnode #t)))				  (touch) ) ) ) ) ) ) ) )	    (or (test varname 'call-sites) '()) ) ) )     side-effect-free-standard-bindings-that-never-return-false)    (when (> removed-nots 0) (debugging 'o "Removed `not' forms" removed-nots))    dirty) );;; Simplifications:(define (register-simplifications class . ss)  (##sys#hash-table-set! simplifications class ss) )(register-simplifications '##core#call ;; (<named-call> ...) -> (<primitive-call/inline> ...) `((##core#call d (##core#variable (a)) b . c)   (a b c d)   ,(lambda (db a b c d)      (let loop ((entries (or (##sys#hash-table-ref substitution-table a) '())))	(cond ((null? entries) #f)	      ((simplify-named-call db d a b (caar entries) (cdar entries) c)	       => (lambda (r)		    (let ((as (assq a simplified-ops)))		      (if as 			  (set-cdr! as (add1 (cdr as)))			  (set! simplified-ops (alist-cons a 1 simplified-ops)) ) )		    r) )	      (else (loop (cdr entries))) ) ) ) ) )(register-simplifications 'let ;; (let ((<var1> (##core#inline <eq-inline-operator> <var0> <const1>))) ;;   (if <var1> <body1> ;;       (let ((<var2> (##core#inline <eq-inline-operator> <var0> <const2>))) ;;         (if <var2> <body2> ;;             <etc.> ;; -> (##core#switch (2) <var0> <const1> <body1> <const2> <body2> <etc.>) ;; - <var1> and <var2> have to be referenced once only. `((let (var1) (##core#inline (op) (##core#variable (var0)) (quote (const1)))	(if d1 (##core#variable (var1))	    body1	    (let (var2) (##core#inline (op) (##core#variable (var0)) (quote (const2)))		 (if d2 (##core#variable (var2))		     body2		     rest) ) ) )   (var0 var1 var2 op const1 const2 body1 body2 d1 d2 rest)   ,(lambda (db var0 var1 var2 op const1 const2 body1 body2 d1 d2 rest)      (and (equal? op eq-inline-operator)	   (immediate? const1)	   (immediate? const2)	   (= 1 (length (get db var1 'references)))	   (= 1 (length (get db var2 'references)))	   (make-node	    '##core#switch	    '(2)	    (list (varnode var0)		  (qnode const1)		  body1		  (qnode const2)		  body2		  rest) ) ) ) ) ;; (let ((<var> (##core#inline <eq-inline-operator> <var0> <const>))) ;;   (if <var> ;;       <body> ;;       (##core#switch <n> <var0> <const1> <body1> ... <rest>) ) ) ;; -> (##core#switch <n+1> <var0> <const> <body> <const1> <body1> ... <rest>) ;; - <var> has to be referenced once only. `((let (var) (##core#inline (op) (##core#variable (var0)) (quote (const)))	(if d (##core#variable (var))	    body	    (##core#switch (n) (##core#variable (var0)) . clauses) ) )   (var op var0 const d body n clauses)   ,(lambda (db var op var0 const d body n clauses)      (and (equal? op eq-inline-operator)	   (immediate? const)	   (= 1 (length (get db var 'references)))	   (make-node	    '##core#switch	    (list (add1 n))	    (cons* (varnode var0)		   (qnode const)		   body		   clauses) ) ) ) )	       ;; (let ((<var1> (##core#undefined))) ;;   (let ((<var2> (##core#undefined))) ;;     ... ;;     (let ((<tmp1> (set! <var1> <x1>)) ;;       (let ((<tmp2> (set! <var2> <x2>))) ;;         ... ;;         <body>) ... ) ;; -> <a simpler sequence of let's> ;; - <tmpI> may not be used. `((let (var1) (##core#undefined ())	more)   (var1 more)   ,(lambda (db var1 more)      (let loop1 ([vars (list var1)] 		  [body more] )	(let ([c (node-class body)]	      [params (node-parameters body)] 	      [subs (node-subexpressions body)] )	  (and (eq? c 'let)	       (null? (cdr params))	       (let* ([val (first subs)]		      [valparams (node-parameters val)]		      [valsubs (node-subexpressions val)] )		 (case (node-class val)		   [(##core#undefined) (loop1 (cons (first params) vars) (second subs))]		   [(set!)		    (let ([allvars (reverse vars)])		      (and (pair? allvars)			   (eq? (first valparams) (first allvars))			   (let loop2 ([vals (list (first valsubs))]				       [vars (cdr allvars)] 				       [body (second subs)] )			     (let ([c (node-class body)]				   [params (node-parameters body)]				   [subs (node-subexpressions body)] )			       (cond [(and (eq? c 'let)					   (null? (cdr params))					   (not (get db (first params) 'references))					   (pair? vars)					   (eq? 'set! (node-class (first subs)))					   (eq? (car vars) (first (node-parameters (first subs)))) )				      (loop2 (cons (first (node-subexpressions (first subs))) vals)					     (cdr vars)					     (second subs) ) ]				     [(null? vars)				      (receive (n progress) 					  (reorganize-recursive-bindings allvars (reverse vals) body) 					(and progress n) ) ]				     [else #f] ) ) ) ) ) ]		   [else #f] ) ) ) ) ) ) ) ;; (let ((<var1> <var2>)) ;;   (<var1> ...) ) ;; -> (<var2> ...) ;; - <var1> used only once #| this doesn't seem to work (Sven Hartrumpf): `((let (var1) (##core#variable (var2))	(##core#call p (##core#variable (var1)) . more) ) ; `p' was `#t', bombed also   (var1 var2 p more)   ,(lambda (db var1 var2 p more)      (and (= 1 (length (get db var1 'references)))	   (make-node	    '##core#call p	    (cons (varnode var2) more) ) ) ) ) |# ;; (let ((<var> (##core#inline <op> ...))) ;;   (if <var> <x> <y>) ) ;; -> (if (##core#inline <op> ...) <x> <y>) ;; - <op> may not be the eq-inline operator (so rewriting to "##core#switch" works). ;; - <var> has to be referenced only once. `((let (var) (##core#inline (op) . args)	(if d (##core#variable (var))	    x	    y) )    (var op args d x y)   ,(lambda (db var op args d x y)      (and (not (equal? op eq-inline-operator))	   (= 1 (length (get db var 'references)))	   (make-node	    'if d	    (list (make-node '##core#inline (list op) args)		  x y) ) ) ) ) )(register-simplifications 'if ;; (if <x> ;;     (<var> <y>) ;;     (<var> <z>) ) ;; -> (<var> (##core#cond <x> <y> <z>)) ;; - inline-substitutions have to be enabled (so IF optimizations have already taken place). `((if d1 x       (##core#call d2 (##core#variable (var)) y)       (##core#call d3 (##core#variable (var)) z) )   (d1 d2 d3 x y z var)   ,(lambda (db d1 d2 d3 x y z var)      (and inline-substitutions-enabled	   (make-node	    '##core#call d2	    (list (varnode var)		  (make-node '##core#cond '() (list x y z)) ) ) ) ) ) ;; (if (##core#inline <memXXX> <x> '(<c1> ...)) ...) ;; -> (let ((<var> <x>)) ;;      (if (##core#cond (##core#inline XXX? <var> '<c1>) #t ...) ...) ;; - there is a limit on the number of items in the list of constants. `((if d1 (##core#inline (op) x (quote (clist)))       y

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -