Re: gsoc: New compiler (almost) ANSI conforming, progress report.

Charles Zhang <[email protected]> Tue, 5 Jun 2018 00:11:08 -0400
Newsgroups gmane.lisp.clisp.devel
Message-ID <CAB=SSS=F_7ftsNz3tm00zXvMMTvhb6aAT-c3qFtGQyqigfQTmg@mail.gmail.com>
I figured out the macroexpansion stuff, so now I can do stuff like
(macrolet ((%m (w) `(cadr ,w)))
    (let ((z (list 3 4)))
      (macrolet ((%m (x) `(car ,x)))
        (let ((y (list 1 2)))
          (values
           (%m y) (%m z)
           (setf (%m y) 6)
           (setf (%m z) 'a)
           y z)))))
correctly. I noticed that there is no way to make #<SPECIAL REFERENCE>
objects, as that's only marked in C, unlike SYSTEM::MAKE-MACRO, for
example. It's probably not something macroexpansion needs though.

On Sun, Jun 3, 2018 at 9:52 PM, Charles Zhang <[email protected]> wrote:
> Hello clisp, Bruno, Sam
>
> Cleavir + CLISP can now pass almost every test in the
> data-and-control-flow portion of cl-ansi-test-suite. The only failing
> tests there seem to be issues in CLISP itself. (See some issues I
> opened on GitLab.) That means that every special operator, dynamic
> variables, closures, non-local exits (both lexical and dynamic) and
> function calls *seem* to work correctly now.
>
> So far, I have handled macroexpansion by just calling macroexpanders
> with the null macroexpansion environment #(NIL NIL). Since I am trying
> to leverage CLISP's macro definitions as much as possible, I'd like to
> know for what type of macros this will break down for CLISP. I'm not
> quite sure which information I really need to make all macros work.
>
> About the compiler, the code produced currently looks like it is
> promising in some ways, and bad in others. For example, since I am
> translating an SSA flow graph to byte code directly, the code looks
> like it is trying to use the stack as a register machine, and
> therefore at times LOADs and and PUSHs a lot. On the other hand, flow
> sensitive information is readily apparent and it should be easy to
> write previously impossible optimizations. To demonstrate, consider
> the following:
>
> (disassemble '(lambda (z)
>                (let ((x 'e))
>                  (values
>                   (case z
>                     (1 (setq x 'a) 'w)
>                     (2 (setq x 'b) 'y)
>                     (t (setq x 'c) 'z))
>                   x))))
> Disassembly of function :LAMBDA
> (CONST 0) = E
> (CONST 1) = 1
> (CONST 2) = A
> (CONST 3) = W
> (CONST 4) = 2
> (CONST 5) = B
> (CONST 6) = Y
> (CONST 7) = C
> (CONST 8) = Z
> 1 required argument
> 0 optional arguments
> No rest parameter
> No keyword parameters
> 23 byte-code instructions:
> 0     (CONST&PUSH 0)                      ; E
> 1     (LOAD&PUSH 2)
> 2     (JMPIFEQTO 1 L18)                   ; 1
> 5     (LOAD&PUSH 2)
> 6     (JMPIFEQTO 4 L23)                   ; 2
> 9     (CONST 7)                           ; C
> 10    (STORE 0)
> 11    (CONST 8)                           ; Z
> 12    L12
> 12    (PUSH)
> 13    (LOAD&PUSH 1)
> 14    (STACK-TO-MV 2)
> 16    (SKIP&RET 3)
> 18    L18
> 18    (CONST 2)                           ; A
> 19    (STORE 0)
> 20    (CONST 3)                           ; W
> 21    (JMP L12)
> 23    L23
> 23    (CONST 5)                           ; B
> 24    (STORE 0)
> 25    (CONST 6)                           ; Y
> 26    (JMP L12)
>
> vs.
> (disassemble (cleavir-compile '(lambda (z)
>                                                (let ((x 'e))
>                                                  (values
>                                                   (case z
>                                                     (1 (setq x 'a) 'w)
>                                                     (2 (setq x 'b) 'y)
>                                                     (t (setq x 'c) 'z))
>                                                   x)))))
>
> Disassembly of function NIL
> (CONST 0) = 1
> (CONST 1) = NIL
> (CONST 2) = 2
> (CONST 3) = NIL
> (CONST 4) = C
> (CONST 5) = Z
> (CONST 6) = B
> (CONST 7) = Y
> (CONST 8) = A
> (CONST 9) = W
> 1 required argument
> 0 optional arguments
> No rest parameter
> No keyword parameters
> 32 byte-code instructions:
> 0     (LOAD&PUSH 1)
> 1     (CONST&PUSH 0)                      ; 1
> 2     (CALLS2&PUSH 19)                    ; EQL
> 4     (LOAD&PUSH 0)
> 5     (JMPIFEQTO 1 L17)                   ; NIL
> 8     (JMP L37)
> 10    L10
> 10    (LOAD&PUSH 0)
> 11    (LOAD&PUSH 2)
> 12    (CALLSR 2 29)                       ; VALUES
> 15    (SKIP&RET 5)
> 17    L17
> 17    (LOAD&PUSH 2)
> 18    (CONST&PUSH 2)                      ; 2
> 19    (CALLS2&PUSH 19)                    ; EQL
> 21    (LOAD&PUSH 0)
> 22    (JMPIFEQTO 3 L27)                   ; NIL
> 25    (JMP L32)
> 27    L27
> 27    (CONST 4)                           ; C
> 28    (STORE 0)
> 29    (CONST&PUSH 5)                      ; Z
> 30    (JMP L10)
> 32    L32
> 32    (CONST 6)                           ; B
> 33    (STORE 0)
> 34    (CONST&PUSH 7)                      ; Y
> 35    (JMP L10)
> 37    L37
> 37    (CONST&PUSH 8)                      ; A
> 38    (CONST&PUSH 9)                      ; W
> 39    (JMP L10)
>
> It's readily apparent that the Cleavir code is not using the best
> choice of branching instructions, duplicating constants, not
> minimizing jumps, and PUSHing and LOADing unnecessarily. However, the
> Cleavir code does not mention the constant 'e at all, because it's
> obvious from the SSA flow graph that 'e is never used, and hence, dead
> code elimination kills it. The passes that I've already written myself
> are the SSA conversion, dead code elimination, and copy propogation
> passes. Adding more dataflow analyses should be straightforward in
> this framework, especially with SSA done.
>
> For now, I am still focusing on correctness, before jumping to more
> sophisticated optimizations like conditional constant propogation or
> fixing some things like special casing for the various branch
> instructions. I wonder how I should integrate this new compiler to
> toplevel functions like COMPILE-FILE/EVAL. Would it make sense to have
> a dynamic variable like *use-cleavir* that switches on the new
> compiler, or a keyword parameter to COMPILE/COMPILE-FILE? When I tried
> using a dynamic variable, I ran into the issue where CLOS methods
> would try and randomly recompile using Cleavir when I had only meant
> to compile one form with Cleavir, since it's heavily CLOS based. Still
> not quite sure how to tie all this toplevel/frontend stuff together.
>
> Charles



-- 
Class of 2021

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
clisp-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/clisp-devel