cisco / ChezScheme

Chez Scheme
Apache License 2.0
6.97k stars 986 forks source link

How to print pass results using trace-define-pass? #581

Closed maoif closed 3 years ago

maoif commented 3 years ago

I saw in docs of nanopass that one can use (trace-define-pass) to make the compiler emit the output of every pass. I changed some of the passes in cpnanopass.ss to (trace-define-pass) but the newly compiled Chez Scheme still does not emit pass results when I'm using either (compile) or (compile-file) or other similar procedures.

Is there any way to see pass results?

akeep commented 3 years ago

You can use trace-define-pass to have it trace the output of the pass. I'm not sure which pass you changed, but it is possible you were getting the system version of the boot file instead of the one with your modification in it. You can explicitly load it by specifying the boot files on the command line:

scheme -b petite.boot -b scheme.boot

Where, petite.boot and scheme.boot are the files in <machine-type>/boot/<machine-type>. Another potential issue, is that if you are testing a simple expression on the repl, the compiler may not be invoked, because the interpreter will just be used. You can turn this off by setting the compile-interpret-simple parameter to #f. For instance, I instrumented the np-recognize-let pass, and got the following results:

% scheme -b cs/a6osx/boot/a6osx/petite.boot -b cs/a6osx/boot/a6osx/scheme.boot
Chez Scheme Version 9.5.5
Copyright 1984-2020 Cisco Systems, Inc.

> (compile-interpret-simple #f)
> (compile `((lambda (x) (+ x x)) 5))
|(np-recognize-let
   (case-lambda
     #<info-lambda #(libspec main 0) (0) #f #f ()>
     [clause
      ()
      0
      (call
        #<info>
        #[#{primref a0xltlrcpeygsahopkplcn-2} compile 34 (1 2)]
        '((lambda (x) (+ x x)) 5))]))
|(case-lambda
   #<info-lambda #(libspec main 0) (0) #f #f ()>
   [clause
    ()
    0
    (call
      #<info>
      #[#{primref a0xltlrcpeygsahopkplcn-2} compile 34 (1 2)]
      '((lambda (x) (+ x x)) 5))])
|(np-recognize-let
   (case-lambda
     #<info-lambda #(libspec main 0) (0) #f #f ()>
     [clause () 0 '10]))
|(case-lambda #<info-lambda #(libspec main 0) (0) #f #f ()> [clause () 0 '10])
10

All of that said, we have also left a tool for tracing passes in the compiler. It is a little different can trace-define-pass, because it does not how the input to the pass, just the output, however, you can simply print the output of the pass before it if you'd like to see the transform. This is enabled by the internal primitive $np-tracer, because it is not exposed, you need to specify it using the explicit primitive syntax: #%$np-tracer. For instance, we could trace the np-recognize-let in an uninstrumented version of the compiler:

% scheme
Chez Scheme Version 9.5.5
Copyright 1984-2020 Cisco Systems, Inc.

> (compile-interpret-simple #f)
> (compile `((lambda (x) (+ x x)) 5))
10
> (#%$np-tracer 'np-recognize-let)
> (compile `((lambda (x) (+ x x)) 5))
output of np-recognize-let:
(case-lambda
  [clause
   ()
   0
   (#[#{primref a0xltlrcpeygsahopkplcn-2} compile 34 (1 2)]
     '((lambda (x) (+ x x)) 5))])
output of np-recognize-let:
(case-lambda [clause () 0 '10])
10

You can trace all passes (or at least all passes in the cpnanopass section of the code) by specifying #t to $np-tracer.

It is also possible to see a version of the generated assembly output using the internal primitive $assembly-output, again with the #% prefix for explicitly specifying a primitive. It takes either a textual output port, or #t to generate output to standard out:

> (#%$assembly-output #t)
> (compile `((lambda (x) (+ x x)) 5))
dcl.2:
0:       subi           (imm 1), $trap
5:       beq            lt.1(37)
ej.0:
7:       movi           (literal 0 (object ((...) 5))), %r8
17:      movi           (literal 0 (object compile)), %xp
27:      mov            (disp 5 %xp), %cp
32:      movi           (imm 1), %ac0
39:      jmp            (disp 13 %xp)
lt.1:
44:      addi           (imm 8), %sfp
docall.3:
48:      lea            (riprel 48), %rcx
55:      mov            %rcx, (disp 0 %sfp)
59:      movi           (imm 4294967295), %ts
69:      jmp            %ts
71:      relocation:    (x86_64-jump 65 (library-code #(libspec event 32817)))
rpl.4:
71:      livemask:      0
79:      code-top-link  
87:      frame size:    8
95:      mrv point:     (abs 168 (code #($c-func (...) #f #f #f) 0 0 #f ...))
mrvl.5:
103:     subi           (imm 8), %sfp
107:     bra            ej.0(-102)
109:     <end>

dcl.6:
0:       movi           (imm 80), %ac0
7:       jmp            (disp 0 %sfp)
11:      <end>
10

Hope that helps!

maoif commented 3 years ago

You can use trace-define-pass to have it trace the output of the pass. I'm not sure which pass you changed, but it is possible you were getting the system version of the boot file instead of the one with your modification in it. You can explicitly load it by specifying the boot files on the command line:

scheme -b petite.boot -b scheme.boot

Where, petite.boot and scheme.boot are the files in <machine-type>/boot/<machine-type>. Another potential issue, is that if you are testing a simple expression on the repl, the compiler may not be invoked, because the interpreter will just be used. You can turn this off by setting the compile-interpret-simple parameter to #f. For instance, I instrumented the np-recognize-let pass, and got the following results:

% scheme -b cs/a6osx/boot/a6osx/petite.boot -b cs/a6osx/boot/a6osx/scheme.boot
Chez Scheme Version 9.5.5
Copyright 1984-2020 Cisco Systems, Inc.

> (compile-interpret-simple #f)
> (compile `((lambda (x) (+ x x)) 5))
|(np-recognize-let
   (case-lambda
     #<info-lambda #(libspec main 0) (0) #f #f ()>
     [clause
      ()
      0
      (call
        #<info>
        #[#{primref a0xltlrcpeygsahopkplcn-2} compile 34 (1 2)]
        '((lambda (x) (+ x x)) 5))]))
|(case-lambda
   #<info-lambda #(libspec main 0) (0) #f #f ()>
   [clause
    ()
    0
    (call
      #<info>
      #[#{primref a0xltlrcpeygsahopkplcn-2} compile 34 (1 2)]
      '((lambda (x) (+ x x)) 5))])
|(np-recognize-let
   (case-lambda
     #<info-lambda #(libspec main 0) (0) #f #f ()>
     [clause () 0 '10]))
|(case-lambda #<info-lambda #(libspec main 0) (0) #f #f ()> [clause () 0 '10])
10

All of that said, we have also left a tool for tracing passes in the compiler. It is a little different can trace-define-pass, because it does not how the input to the pass, just the output, however, you can simply print the output of the pass before it if you'd like to see the transform. This is enabled by the internal primitive $np-tracer, because it is not exposed, you need to specify it using the explicit primitive syntax: #%$np-tracer. For instance, we could trace the np-recognize-let in an uninstrumented version of the compiler:

% scheme
Chez Scheme Version 9.5.5
Copyright 1984-2020 Cisco Systems, Inc.

> (compile-interpret-simple #f)
> (compile `((lambda (x) (+ x x)) 5))
10
> (#%$np-tracer 'np-recognize-let)
> (compile `((lambda (x) (+ x x)) 5))
output of np-recognize-let:
(case-lambda
  [clause
   ()
   0
   (#[#{primref a0xltlrcpeygsahopkplcn-2} compile 34 (1 2)]
     '((lambda (x) (+ x x)) 5))])
output of np-recognize-let:
(case-lambda [clause () 0 '10])
10

You can trace all passes (or at least all passes in the cpnanopass section of the code) by specifying #t to $np-tracer.

It is also possible to see a version of the generated assembly output using the internal primitive $assembly-output, again with the #% prefix for explicitly specifying a primitive. It takes either a textual output port, or #t to generate output to standard out:

> (#%$assembly-output #t)
> (compile `((lambda (x) (+ x x)) 5))
dcl.2:
0:       subi           (imm 1), $trap
5:       beq            lt.1(37)
ej.0:
7:       movi           (literal 0 (object ((...) 5))), %r8
17:      movi           (literal 0 (object compile)), %xp
27:      mov            (disp 5 %xp), %cp
32:      movi           (imm 1), %ac0
39:      jmp            (disp 13 %xp)
lt.1:
44:      addi           (imm 8), %sfp
docall.3:
48:      lea            (riprel 48), %rcx
55:      mov            %rcx, (disp 0 %sfp)
59:      movi           (imm 4294967295), %ts
69:      jmp            %ts
71:      relocation:    (x86_64-jump 65 (library-code #(libspec event 32817)))
rpl.4:
71:      livemask:      0
79:      code-top-link  
87:      frame size:    8
95:      mrv point:     (abs 168 (code #($c-func (...) #f #f #f) 0 0 #f ...))
mrvl.5:
103:     subi           (imm 8), %sfp
107:     bra            ej.0(-102)
109:     <end>

dcl.6:
0:       movi           (imm 80), %ac0
7:       jmp            (disp 0 %sfp)
11:      <end>
10

Hope that helps!

Thanks for your detailed answer!

While I was exploring the code, I noticed define tracer ... and (set! $np-tracer tracer) in the end, but I didn't know one can use the #% syntax to invoke internal primitives, so I manually modified the piece in the body of $xpass😀