66import com .compilerprogramming .ezlang .compiler .nodes .*;
77import com .compilerprogramming .ezlang .compiler .sontypes .*;
88
9+ import java .util .HashSet ;
10+
911public abstract class ASMPrinter {
1012
1113 public static SB print (SB sb , CodeGen code ) {
@@ -17,118 +19,190 @@ public static SB print(SB sb, CodeGen code) {
1719 for ( int i =0 ; i <code ._cfg ._len ; i ++ )
1820 if ( code ._cfg .at (i ) instanceof FunNode fun )
1921 iadr = print (iadr ,sb ,code ,fun ,i );
22+
23+ // Skip padding
24+ while ( ((iadr +7 ) & -8 ) > iadr )
25+ iadr ++;
26+
27+ // constant pool
28+ Encoding enc = code ._encoding ;
29+ if ( enc !=null && !enc ._bigCons .isEmpty () ) {
30+ iadr = (iadr +15 )&-16 ; // pad to 16
31+ HashSet <SONType > targets = new HashSet <>();
32+ sb .p ("--- Constant Pool ------" ).nl ();
33+ // By log size
34+ for ( int log = 3 ; log >= 0 ; log -- ) {
35+ for ( Node op : enc ._bigCons .keySet () ) {
36+ Encoding .Relo relo = enc ._bigCons .get (op );
37+ if ( targets .contains (relo ._t ) ) continue ;
38+ targets .add (relo ._t );
39+ if ( relo ._t .log_size ()==log ) {
40+ sb .hex2 (iadr ).p (" " );
41+ if ( relo ._t instanceof SONTypeTuple tt ) {
42+ for ( SONType tx : tt ._types ) {
43+ switch ( log ) {
44+ case 0 : sb .hex1 (enc .read1 (iadr )); break ;
45+ case 1 : sb .hex2 (enc .read2 (iadr )); break ;
46+ case 2 : sb .hex4 (enc .read4 (iadr )); break ;
47+ case 3 : sb .hex8 (enc .read8 (iadr )); break ;
48+ }
49+ iadr += (1 <<log );
50+ sb .p (" " );
51+ }
52+ } else {
53+ switch ( log ) {
54+ case 0 : sb .hex1 (enc .read1 (iadr )).fix (9 -1 ,"" ); break ;
55+ case 1 : sb .hex2 (enc .read2 (iadr )).fix (9 -2 ,"" ); break ;
56+ case 2 : sb .hex4 (enc .read4 (iadr )).fix (9 -4 ,"" ); break ;
57+ case 3 : sb .hex8 (enc .read8 (iadr )).p (" " ); break ;
58+ }
59+ iadr += (1 <<log );
60+ }
61+ relo ._t .print (sb ).nl ();
62+ }
63+ }
64+ }
65+ }
66+
67+
2068 return sb ;
2169 }
2270
2371 private static int print (int iadr , SB sb , CodeGen code , FunNode fun , int cfgidx ) {
72+ FunNode old =null ;
73+ if ( code ._encoding !=null ) {
74+ old = code ._encoding ._fun ;
75+ code ._encoding ._fun = fun ; // Useful printing after RA
76+ }
2477 // Function header
2578 sb .nl ().p ("---" );
2679 if ( fun ._name != null ) sb .p (fun ._name ).p (" " );
2780 fun .sig ().print (sb );
2881 sb .p ("---------------------------" ).nl ();
82+ iadr = (iadr + 15 )&-16 ; // All function entries padded to 16 align
2983
30-
84+ if ( fun ._frameAdjust != 0 )
85+ iadr = doInst (iadr ,sb ,code ,fun ,cfgidx ,fun ,true ,true );
3186 while ( !(code ._cfg .at (cfgidx ) instanceof ReturnNode ) )
3287 iadr = doBlock (iadr ,sb ,code ,fun ,cfgidx ++);
3388
3489 // Function separator
3590 sb .p ("---" );
3691 fun .sig ().print (sb );
3792 sb .p ("---------------------------" ).nl ();
93+ if ( code ._encoding != null )
94+ code ._encoding ._fun = old ;
3895 return iadr ;
3996 }
4097
41- static private final int encWidth = 8 ;
4298 static private final int opWidth = 5 ;
4399 static private final int argWidth = 30 ;
44100 static int doBlock (int iadr , SB sb , CodeGen code , FunNode fun , int cfgidx ) {
101+ final int encWidth = code ._mach ==null ? 2 : code ._mach .defaultOpSize ()*2 ;
45102 CFGNode bb = code ._cfg .at (cfgidx );
46103 if ( bb != fun && !(bb instanceof IfNode ) && !(bb instanceof CallEndNode ) && !(bb instanceof CallNode ) && !(bb instanceof CProjNode && bb .in (0 ) instanceof CallEndNode ))
47- sb .p (bb instanceof LoopNode ? "LOOP" : "L" ). p (bb . _nid ).p (":" ).nl ();
104+ sb .p (label (bb ) ).p (":" ).nl ();
48105 if ( bb instanceof CallNode ) return iadr ;
49106 final boolean postAlloc = code ._phase .ordinal () > CodeGen .Phase .RegAlloc .ordinal ();
107+ final boolean postEncode = code ._phase .ordinal () >=CodeGen .Phase .Encoding .ordinal ();
50108
51- // Count Phis
52- int nPhi =0 ;
53- for ( ; nPhi <bb .nOuts (); nPhi ++ )
54- if ( !(bb .out (nPhi ) instanceof PhiNode ) )
55- break ;
56-
57- if ( nPhi >0 ) {
58- // Post-alloc phi prints all on one line
109+ boolean once =false ;
110+ for ( Node n : bb .outs () ) {
111+ if ( !(n instanceof PhiNode phi ) ) continue ;
112+ if ( phi ._type instanceof SONTypeMem || phi ._type instanceof SONTypeRPC ) continue ; // Nothing for the hidden ones
113+ // Post-RegAlloc phi prints all on one line
59114 if ( postAlloc ) {
60- sb .fix (4 ," " ).p (" " ).fix (encWidth ,"" ).p (" " );
61- for ( int i =0 ; i <nPhi ; i ++ ) {
62- PhiNode phi = (PhiNode )bb .out (i );
63- if ( !(phi ._type instanceof SONTypeMem || phi ._type instanceof SONTypeRPC ) ) // Nothing for the hidden ones
64- sb .p (phi ._label ).p (':' ).p (code .reg (phi )).p (',' );
65- }
66- sb .unchar ().nl ();
67-
115+ if ( !once ) { once =true ; sb .fix (4 ," " ).p (" " ).fix (encWidth ,"" ).p (" " ); }
116+ sb .p (phi ._label ).p (':' ).p (code .reg (phi ,fun )).p (',' );
68117 } else {
69- for ( int j =0 ; j <nPhi ; j ++ ) {
70- PhiNode phi = (PhiNode )bb .out (j );
71- if ( phi ._type instanceof SONTypeMem || phi ._type instanceof SONTypeRPC ) continue ; // Nothing for the hidden ones
72- sb .fix (4 ," " ).p (" " ).fix (encWidth ,"" ).p (" " ).fix (opWidth ,phi ._label ).p (" " );
73- sb .p (code .reg (phi ));
74- if ( !(phi instanceof ParmNode ) ) {
75- sb .p (" = phi( " );
76- for ( int i =1 ; i <phi .nIns (); i ++ )
77- sb .p ("N" ).p (phi .in (i )._nid ).p ("," );
78- sb .unchar ().p (" )" );
79- }
80- sb .nl ();
118+ // Pre-RegAlloc phi prints one line per
119+ sb .fix (4 ," " ).p (" " ).fix (encWidth ,"" ).p (" " ).fix (opWidth ,phi ._label ).p (" " ).p (code .reg (phi ,fun ));
120+ if ( phi .getClass () == PhiNode .class ) {
121+ sb .p (" = phi( " );
122+ for ( int i =1 ; i <phi .nIns (); i ++ )
123+ sb .p ("N" ).p (phi .in (i )._nid ).p ("," );
124+ sb .unchar ().p (" )" );
81125 }
126+ sb .nl ();
82127 }
83128 }
129+ if ( once ) sb .unchar ().nl ();
84130
85131 // All the non-phis
86- for ( int i =nPhi ; i <bb .nOuts (); i ++ )
87- iadr = doInst (iadr , sb ,code ,fun ,bb ,bb .out (i ),postAlloc );
132+ for ( int i =0 ; i <bb .nOuts (); i ++ )
133+ if ( !(bb .out (i ) instanceof PhiNode ) )
134+ iadr = doInst (iadr , sb ,code , fun , cfgidx , bb .out (i ),postAlloc , postEncode );
88135
89136 return iadr ;
90137 }
91138
92- static int doInst (int iadr , SB sb , CodeGen code , FunNode fun , CFGNode bb , Node n , boolean postAlloc ) {
93- if ( n instanceof CProjNode ) return iadr ;
94- if ( n instanceof CalleeSaveNode && postAlloc ) return iadr ;
139+ static int doInst ( int iadr , SB sb , CodeGen code , FunNode fun , int cfgidx , Node n , boolean postAlloc , boolean postEncode ) {
140+ if ( n ==null || n instanceof CProjNode ) return iadr ;
141+ if ( postAlloc && n instanceof CalleeSaveNode ) return iadr ;
142+ if ( postEncode && n instanceof ProjNode ) return iadr ;
143+ if ( n instanceof MemMergeNode ) return iadr ;
144+ if ( n .getClass () == ConstantNode .class ) return iadr ; // Default placeholders
145+ final int dopz = code ._mach ==null ? 2 : code ._mach .defaultOpSize ();
146+ final int encWidth = dopz *2 ;
95147
96148 // All blocks ending in a Region will need to either fall into or jump
97149 // to this block. Until the post-reg-alloc block layout cleanup, we
98150 // need to assume a jump. There's no real hardware op here, yet.
99- if ( n instanceof RegionNode && !(n instanceof FunNode ) ) {
100- sb .hex4 (iadr ++).p (" " ).fix (encWidth ,"??" ).p (" " ).fix (opWidth ,"JMP" ).p (" " ).fix (argWidth ,"L" +n ._nid ).nl ();
151+ if ( n instanceof RegionNode cfg && !(n instanceof FunNode ) ) {
152+ if ( postEncode ) return iadr ; // All jumps inserted already
153+ while ( cfgidx < code ._cfg ._len -1 ) {
154+ CFGNode next = code ._cfg .at (++cfgidx );
155+ if ( next == n ) return iadr ; // Fall-through, no branch
156+ if ( next .nOuts ()>1 )
157+ break ; // Has code in the block, need to jump around
158+ // No code in the block, can fall through it
159+ }
160+ sb .hex2 (iadr ++).p (" " ).fix (encWidth ,"??" ).p (" " ).fix (opWidth ,"JMP" ).p (" " ).fix (argWidth ,label (cfg )).nl ();
101161 return iadr ;
102162 }
103163
104164 // ProjNodes following a multi (e.g. Call or New results),
105165 // get indent slightly and just print their index & node#
106166 if ( n instanceof ProjNode proj ) {
107167 if ( proj ._type instanceof SONTypeMem ) return iadr ; // Nothing for the hidden ones
108- sb .fix (4 ," " ).p (" " ).fix (encWidth ,"" ).p (" " ).fix (opWidth ,proj ._label ==null ? "---" : proj ._label ).p (" " ).p (code .reg (n )).nl ();
168+ sb .fix (4 ," " ).p (" " ).fix (encWidth ,"" ).p (" " ).fix (opWidth ,proj ._label ==null ? "---" : proj ._label ).p (" " ).p (code .reg (n , fun )).nl ();
109169 return iadr ;
110170 }
111171
112172 // ADDR ENCODING Op--- dst = src op src // Comment
113173 // 1234 abcdefgh ld4 RAX = [Rbase + off] // Comment
114- sb .hex4 (iadr );
115- sb .p (" " );
174+ sb .hex2 (iadr ).p (" " );
116175
117176 // Encoding
118- int size = 1 ; // TODO: Fake encoding size
119- iadr += size ;
120- sb .fix (encWidth ,"??" );
177+ int fatEncoding = 0 ;
178+ if ( code ._encoding != null ) {
179+ int size = code ._encoding ._opLen [n ._nid ];
180+ if ( code ._asmLittle )
181+ for ( int i =0 ; i <Math .min (size ,dopz ); i ++ )
182+ sb .hex1 (code ._encoding ._bits .buf ()[iadr ++]);
183+ else {
184+ iadr += Math .min (size ,dopz );
185+ for ( int i =0 ; i <Math .min (size ,dopz ); i ++ )
186+ sb .hex1 (code ._encoding ._bits .buf ()[iadr -i -1 ]);
187+ }
188+ for ( int i =size *2 ; i <encWidth ; i ++ )
189+ sb .p (" " );
190+ fatEncoding = size - (encWidth >>1 ); // Not-printed parts of encoding
191+ } else
192+ sb .fix (encWidth ,"" );
121193 sb .p (" " );
122194
123195 // Op; generally "ld4" or "call"
124- sb .fix (opWidth , n instanceof MachNode mach ? mach .op () : n .label ());
125- sb .p (" " );
196+ sb .fix (opWidth , n instanceof MachNode mach ? mach .op () : n .label ()).p (" " );
126197
127198 // General asm args
199+ String isMultiOp = null ;
128200 if ( n instanceof MachNode mach ) {
129201 int old = sb .len ();
130202 mach .asm (code ,sb );
131- sb .fix (argWidth -(sb .len ()-old ),"" ); // Pad out
203+ int len = sb .len ();
204+ isMultiOp = isMultiOp (sb ,old ,len );
205+ sb .fix (argWidth -(len -old ),"" ); // Pad out
132206
133207 } else if ( !(n ._type instanceof SONTypeMem ) ) {
134208 // Room for some inputs
@@ -149,14 +223,64 @@ static int doInst(int iadr, SB sb, CodeGen code, FunNode fun, CFGNode bb, Node n
149223
150224 sb .nl ();
151225
226+ // Printing more op bits than fit
227+ if ( isMultiOp != null && code ._encoding != null ) {
228+ // Multiple ops, template style, no RA, no scheduling. Print out
229+ // one-line-per-newline, with encoding bits up front.
230+ int size = code ._encoding ._opLen [n ._nid ];
231+ int off = Math .min (size ,dopz );
232+ while ( isMultiOp !=null ) {
233+ sb .hex2 (iadr ).p (" " );
234+ int len = Math .min (size -off ,dopz );
235+ for ( int i =0 ; i <len ; i ++ )
236+ sb .hex1 (code ._encoding ._bits .buf ()[iadr ++]);
237+ off += len ;
238+ for ( int i =len ; i <dopz ; i ++ ) sb .p (" " );
239+ sb .p (" " );
240+ int x = isMultiOp .indexOf ('\n' );
241+ if ( x == -1 ) { // Last line
242+ sb .p (isMultiOp ).nl ();
243+ isMultiOp = null ;
244+ } else {
245+ sb .p (isMultiOp .substring (0 ,x +1 )); // Includes the newline
246+ isMultiOp = isMultiOp .substring (x +1 );
247+ }
248+
249+ }
250+
251+ } else if ( fatEncoding > 0 ) {
252+ // Extra bytes past the default encoding width, all put on a line by
253+ // themselves. X86 special for super long encodings
254+ sb .hex2 (iadr ).p (" " );
255+ for ( int i =0 ; i <fatEncoding ; i ++ )
256+ sb .hex1 (code ._encoding ._bits .buf ()[iadr ++]);
257+ sb .nl ();
258+ }
259+
260+
152261 // MultiNodes are immediately followed by projection(s)
153262 if ( !(n instanceof CFGNode ) && n instanceof MultiNode ) {
154263 for ( Node proj : n ._outputs ) {
155- assert proj instanceof ProjNode ;
156- doInst (iadr ,sb ,code ,fun ,bb , proj ,postAlloc );
264+ if ( proj instanceof ProjNode ) // it could also be an ante-dep
265+ doInst (iadr ,sb ,code ,fun , cfgidx , proj ,postAlloc , postEncode );
157266 }
158267 }
159268
160269 return iadr ;
161270 }
271+
272+ private static String label ( CFGNode bb ) {
273+ return (bb instanceof LoopNode ? "LOOP" : "L" )+bb ._nid ;
274+ }
275+
276+ private static String isMultiOp (SB sb , int old , int len ) {
277+ for ( int i =old ; i <len ; i ++ )
278+ if ( sb .at (i )=='\n' ) {
279+ String s = sb .subString (i +1 ,len );
280+ sb .setLen (i );
281+ return s ;
282+ }
283+ return null ;
284+ }
285+
162286}
0 commit comments