Skip to content

Instantly share code, notes, and snippets.

@ehaliewicz
Last active December 14, 2015 11:19
Show Gist options
  • Save ehaliewicz/5078266 to your computer and use it in GitHub Desktop.
Save ehaliewicz/5078266 to your computer and use it in GitHub Desktop.
Compiler inlining example
;; '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