Last active
December 14, 2015 11:19
-
-
Save ehaliewicz/5078266 to your computer and use it in GitHub Desktop.
Compiler inlining example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 'val is the register where the return value of compiling goes | |
;; 'next is the requested type of compiler linkage, how the compiler will finish off the compiled code | |
;; 'return linkage returns to the state on top of the stack (to return from a function) | |
;; 'next linkage just continues onto whatever is the next instruction after the compiled instructions | |
;; any other linkage assumes a label, | |
;; i.e. (compile '(+ 1 2 3) 'val 'end) assumes 'end is a label somewhere,and jumps to it after calculating (+ 1 2 3) | |
(statements (ec-compile '(+ 1 2 3) 'val 'next)) ;; compile without inlining/open-coding | |
=> | |
'((ASSIGN PROC (OP LOOKUP-VARIABLE-VALUE) (CONST *) (REG ENV)) ;; lookup * function and place in proc register | |
(ASSIGN VAL (CONST 3)) ;; assign 3 to register | |
(ASSIGN ARGL (OP LIST) (REG VAL)) ;; concatenate 3 to arglist register | |
(ASSIGN VAL (CONST 2)) ;; assign 2 to register | |
(ASSIGN ARGL (OP CONS) (REG VAL) (REG ARGL)) ;; concatenate 2 to arglist register | |
(ASSIGN VAL (CONST 1)) ;; assign 1 to register | |
(ASSIGN ARGL (OP CONS) (REG VAL) (REG ARGL)) ;; concatenate 1 to arglist register | |
(TEST (OP PRIMITIVE-PROCEDURE?) (REG PROC)) ;; is + primitive? | |
(BRANCH (LABEL PRIMITIVE-BRANCH1)) ;; if it is, goto primitive branch | |
COMPILED-BRANCH2 ;; compile procedure branch | |
(ASSIGN CONTINUE (LABEL AFTER-CALL3)) ;; set up continue register to jump to end | |
(ASSIGN VAL (OP COMPILED-PROCEDURE-ENTRY) (REG PROC)) ;; assign body of compiled procedure to val | |
(GOTO (REG VAL)) ;; goto val (body of procedure) | |
;; (procedure will eventually jump to the value in the | |
;; continue register, which is now 'after-call3) | |
PRIMITIVE-BRANCH1 | |
(ASSIGN VAL (OP APPLY-PRIMITIVE-PROCEDURE) (REG PROC) (REG ARGL)) ;; if it is a primitive procedure (builtin, not compiled), | |
;;then apply the procedure in proc to the arguments in argl | |
AFTER-CALL3) | |
(statements (ec-compile '(+ 1 2 3) 'val 'next) ;; compile with inlining/open-coding | |
=> | |
'((ASSIGN ARG1 (CONST 1)) ;; load vars into extra registers | |
(ASSIGN ARG2 (CONST 2)) | |
(ASSIGN ARG3 (CONST 3)) | |
(ASSIGN VAL (OP +) (REG ARG1) (REG ARG2)) ;; and apply primitive functions inline | |
(ASSIGN VAL (OP +) (REG VAL) (REG ARG3))) | |
;; i have 3 registers that are unused by the lisp runtime, so I can inline function calls with up to 3 operands | |
;; in the case where an inline-able function has more than 3 operands, they are re-organized to maximize inlining, though operands spill onto the stack | |
;; (technically, i could use more than 3 registers for this, but I would have to prove that they are unused with analysis) | |
(statements (ec-compile '(+ 1 2 3 4 5) 'val 'next) | |
;; equivalent to (ec-compile '(+ 1 2 (+ 3 4 5)) 'val 'next) | |
=> | |
'((ASSIGN ARG1 (CONST 1)) ;; load first op into arg1 | |
(ASSIGN ARG2 (CONST 2)) ;; load second op into arg2 | |
(ASSIGN ARG1 (OP +) (REG ARG1) (REG ARG2)) ;; load arg1(1) + arg2 (2) into arg1 | |
(SAVE ARG1) ;; save arg1 (3) | |
(ASSIGN ARG1 (CONST 3)) ;; load third op into arg1 | |
(ASSIGN ARG2 (CONST 4)) ;; load fourth op into arg2 | |
(ASSIGN ARG1 (OP +) (REG ARG1) (REG ARG2)) ;; load arg1(3) + arg2(4) into arg1 | |
(ASSIGN ARG3 (CONST 5)) ;; load fifth op into arg3 | |
(ASSIGN ARG3 (OP +) (REG ARG1) (REG ARG3)) ;; load arg1(7)+arg3(5) into arg3 | |
(RESTORE ARG1) ;; reload previous addition into arg1 | |
(ASSIGN VAL (OP +) (REG ARG1) (REG ARG3))) ;; and set target register to arg1(3)+arg3(12) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment