diff options
author | Andy Wingo <wingo@pobox.com> | 2021-02-25 14:53:13 +0100 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2021-02-25 16:08:02 +0100 |
commit | 636ae1d51048481c012f54492ed1049078e15408 (patch) | |
tree | 7f3366974bd01b327b4bb2ab67c4f821ff086267 /module/system | |
parent | 3fcc0eb27b80892d3cb72ce72a4d119b873c0f82 (diff) | |
download | guile-636ae1d51048481c012f54492ed1049078e15408.tar.gz |
Optimize run-time init and relocation procedure
* module/system/vm/assembler.scm (<asm>, make-assembler)
(intern-constant, emit-init-constants): Instead of loading a dependent
value each time it's needed in the relocation procedure, eagerly patch
values when they are created. Allows keeping values in registers, which
decreases code size.
Diffstat (limited to 'module/system')
-rw-r--r-- | module/system/vm/assembler.scm | 166 |
1 files changed, 109 insertions, 57 deletions
diff --git a/module/system/vm/assembler.scm b/module/system/vm/assembler.scm index 5be16f6a8..e5d81525a 100644 --- a/module/system/vm/assembler.scm +++ b/module/system/vm/assembler.scm @@ -545,8 +545,17 @@ N-byte unit." ;; (constants asm-constants set-asm-constants!) - ;; A list of instructions needed to initialize the constants. Will - ;; run in a thunk with 2 local variables. + ;; A vhash of label to init descriptors, where an init descriptor is + ;; #(EMIT-INIT STATIC? PATCHES). EMIT-INIT, if present, is a + ;; procedure taking the asm and the label as arguments. Unless the + ;; object is statically allocatable, in which case it can be loaded + ;; via make-non-immediate rather than static-ref, EMIT-INIT should + ;; also initialize the corresponding cell for any later static-ref. + ;; If STATIC? is true, the value can be loaded with + ;; emit-make-non-immediate, otherwise it's emit-static-ref. A bit + ;; confusing but that's how it is. PATCHES is a list of (DEST-LABEL + ;; . FIELD) pairs, indicating locations to which to patch the value. + ;; Like asm-constants, order is important. ;; (inits asm-inits set-asm-inits!) @@ -582,7 +591,7 @@ target." (make-asm (make-u32vector 1000) 0 0 (make-hash-table) '() word-size endianness - vlist-null '() + vlist-null vlist-null (make-string-table) 1 '() '() '())) @@ -1249,52 +1258,77 @@ used to reference it. If the object is already present in the constant table, its existing label is used directly." (define (recur obj) (intern-constant asm obj)) - (define (field dst n obj) - (let ((src (recur obj))) - (if src - (if (statically-allocatable? obj) - `((static-patch! ,dst ,n ,src)) - `((static-ref 1 ,src) - (static-set! 1 ,dst ,n))) - '()))) - (define (intern obj label) + (define (add-desc! label desc) + (set-asm-inits! asm (vhash-consq label desc (asm-inits asm)))) + (define (init-descriptor obj) + (let ((label (recur obj))) + (cond + ((not label) #f) + ((vhash-assq label (asm-inits asm)) => cdr) + (else + (let ((desc (vector #f #t '()))) + (add-desc! label desc) + desc))))) + (define (add-patch! dst field obj) + (match (init-descriptor obj) + (#f #f) + ((and desc #(emit-init emit-load patches)) + (vector-set! desc 2 (acons dst field patches))))) + (define (add-init! dst init) + (add-desc! dst (vector init #f '()))) + (define (intern! obj label) + (define (patch! field obj) (add-patch! label field obj)) + (define (init! emit-init) (add-init! label emit-init)) (cond ((pair? obj) - (append (field label 0 (car obj)) - (field label 1 (cdr obj)))) + (patch! 0 (car obj)) + (patch! 1 (cdr obj))) ((simple-vector? obj) - (let lp ((i 0) (inits '())) - (if (< i (vector-length obj)) - (lp (1+ i) - (append-reverse (field label (1+ i) (vector-ref obj i)) - inits)) - (reverse inits)))) + (let lp ((i 0)) + (when (< i (vector-length obj)) + (patch! (1+ i) (vector-ref obj i)) + (lp (1+ i))))) ((syntax? obj) - (append (field label 1 (syntax-expression obj)) - (field label 2 (syntax-wrap obj)) - (field label 3 (syntax-module obj)) - (field label 4 (syntax-source obj)))) - ((stringbuf? obj) '()) + (patch! 1 (syntax-expression obj)) + (patch! 2 (syntax-wrap obj)) + (patch! 3 (syntax-module obj)) + (patch! 4 (syntax-source obj))) + ((stringbuf? obj)) ((static-procedure? obj) - `((static-patch! ,label 1 ,(static-procedure-code obj)))) - ((cache-cell? obj) '()) + ;; Special case, as we can't load the procedure's code using + ;; make-non-immediate. + (let* ((code (static-procedure-code obj)) + (init (lambda (asm label) + (emit-static-patch! asm label 1 code) + #f))) + (add-desc! label (vector init #t '())))) + ((cache-cell? obj)) ((symbol? obj) (unless (symbol-interned? obj) (error "uninterned symbol cannot be saved to object file" obj)) - `((make-non-immediate 1 ,(recur (symbol->string obj))) - (string->symbol 1 1) - (static-set! 1 ,label 0))) + (let ((str-label (recur (symbol->string obj)))) + (init! (lambda (asm label) + (emit-make-non-immediate asm 1 str-label) + (emit-string->symbol asm 1 1) + (emit-static-set! asm 1 label 0) + 1)))) ((string? obj) - `((static-patch! ,label 1 ,(recur (make-stringbuf obj))))) + (patch! 1 (make-stringbuf obj))) ((keyword? obj) - `((static-ref 1 ,(recur (keyword->symbol obj))) - (symbol->keyword 1 1) - (static-set! 1 ,label 0))) + (let ((sym-label (recur (keyword->symbol obj)))) + (init! (lambda (asm label) + (emit-static-ref asm 1 sym-label) + (emit-symbol->keyword asm 1 1) + (emit-static-set! asm 1 label 0) + 1)))) ((number? obj) - `((make-non-immediate 1 ,(recur (number->string obj))) - (string->number 1 1) - (static-set! 1 ,label 0))) - ((uniform-vector-backing-store? obj) '()) + (let ((str-label (recur (number->string obj)))) + (init! (lambda (asm label) + (emit-make-non-immediate asm 1 str-label) + (emit-string->number asm 1 1) + (emit-static-set! asm 1 label 0) + 1)))) + ((uniform-vector-backing-store? obj)) ((simple-uniform-vector? obj) (let ((width (case (array-type obj) ((vu8 u8 s8) 1) @@ -1306,23 +1340,22 @@ table, its existing label is used directly." ((u64 s64 f64 c64) 8) (else (error "unhandled array type" obj))))) - `((static-patch! ,label 2 - ,(recur (make-uniform-vector-backing-store - (uniform-array->bytevector obj) - width)))))) + (patch! 2 + (make-uniform-vector-backing-store + (uniform-array->bytevector obj) + width)))) ((array? obj) - `((static-patch! ,label 1 ,(recur (shared-array-root obj))))) + (patch! 1 (shared-array-root obj))) (else (error "don't know how to intern" obj)))) (cond ((immediate-bits asm obj) #f) ((vhash-assoc obj (asm-constants asm)) => cdr) (else - ;; Note that calling intern may mutate asm-constants and asm-inits. - (let* ((label (gensym "constant")) - (inits (intern obj label))) + (let ((label (gensym "constant"))) + ;; Note that calling intern may mutate asm-constants and asm-inits. + (intern! obj label) (set-asm-constants! asm (vhash-cons obj label (asm-constants asm))) - (set-asm-inits! asm (append-reverse inits (asm-inits asm))) label)))) (define (intern-non-immediate asm obj) @@ -1742,17 +1775,36 @@ corresponding linker symbol for the start of the section." "If there is writable data that needs initialization at runtime, emit a procedure to do that and return its label. Otherwise return @code{#f}." - (let ((inits (asm-inits asm))) - (and (not (null? inits)) + (let* ((inits (asm-inits asm))) + (and (not (vlist-null? inits)) (let ((label (gensym "init-constants"))) - (emit-text asm - `((begin-program ,label ()) - (assert-nargs-ee/locals 1 1) - ,@(reverse inits) - (reset-frame 1) - (load-constant 0 ,*unspecified*) - (return-values) - (end-program))) + (emit-begin-program asm label '()) + (emit-assert-nargs-ee/locals asm 1 1) + (let lp ((n (1- (vlist-length inits)))) + (match (vlist-ref inits n) + ((label . #(#f #t ((dst . field)))) + ;; Special case in which emit-static-patch is actually + ;; an optimization. + (emit-static-patch! asm dst field label)) + ((label . #(emit-init static? patches)) + (let ((slot-from-init (and emit-init (emit-init asm label)))) + (unless (null? patches) + (let ((slot (or slot-from-init + (begin + (if static? + (emit-make-non-immediate asm 1 label) + (emit-static-ref asm 1 label)) + 1)))) + (for-each (match-lambda + ((dst . offset) + (emit-static-set! asm slot dst offset))) + patches)))))) + (unless (zero? n) + (lp (1- n)))) + (emit-reset-frame asm 1) + (emit-load-constant asm 0 *unspecified*) + (emit-return-values asm) + (emit-end-program asm) label)))) (define (link-data asm data name) |