6
6
import com .compilerprogramming .ezlang .compiler .nodes .*;
7
7
import com .compilerprogramming .ezlang .compiler .sontypes .*;
8
8
9
+ import java .util .HashSet ;
10
+
9
11
public abstract class ASMPrinter {
10
12
11
13
public static SB print (SB sb , CodeGen code ) {
@@ -17,118 +19,190 @@ public static SB print(SB sb, CodeGen code) {
17
19
for ( int i =0 ; i <code ._cfg ._len ; i ++ )
18
20
if ( code ._cfg .at (i ) instanceof FunNode fun )
19
21
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
+
20
68
return sb ;
21
69
}
22
70
23
71
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
+ }
24
77
// Function header
25
78
sb .nl ().p ("---" );
26
79
if ( fun ._name != null ) sb .p (fun ._name ).p (" " );
27
80
fun .sig ().print (sb );
28
81
sb .p ("---------------------------" ).nl ();
82
+ iadr = (iadr + 15 )&-16 ; // All function entries padded to 16 align
29
83
30
-
84
+ if ( fun ._frameAdjust != 0 )
85
+ iadr = doInst (iadr ,sb ,code ,fun ,cfgidx ,fun ,true ,true );
31
86
while ( !(code ._cfg .at (cfgidx ) instanceof ReturnNode ) )
32
87
iadr = doBlock (iadr ,sb ,code ,fun ,cfgidx ++);
33
88
34
89
// Function separator
35
90
sb .p ("---" );
36
91
fun .sig ().print (sb );
37
92
sb .p ("---------------------------" ).nl ();
93
+ if ( code ._encoding != null )
94
+ code ._encoding ._fun = old ;
38
95
return iadr ;
39
96
}
40
97
41
- static private final int encWidth = 8 ;
42
98
static private final int opWidth = 5 ;
43
99
static private final int argWidth = 30 ;
44
100
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 ;
45
102
CFGNode bb = code ._cfg .at (cfgidx );
46
103
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 ();
48
105
if ( bb instanceof CallNode ) return iadr ;
49
106
final boolean postAlloc = code ._phase .ordinal () > CodeGen .Phase .RegAlloc .ordinal ();
107
+ final boolean postEncode = code ._phase .ordinal () >=CodeGen .Phase .Encoding .ordinal ();
50
108
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
59
114
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 (',' );
68
117
} 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 (" )" );
81
125
}
126
+ sb .nl ();
82
127
}
83
128
}
129
+ if ( once ) sb .unchar ().nl ();
84
130
85
131
// 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 );
88
135
89
136
return iadr ;
90
137
}
91
138
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 ;
95
147
96
148
// All blocks ending in a Region will need to either fall into or jump
97
149
// to this block. Until the post-reg-alloc block layout cleanup, we
98
150
// 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 ();
101
161
return iadr ;
102
162
}
103
163
104
164
// ProjNodes following a multi (e.g. Call or New results),
105
165
// get indent slightly and just print their index & node#
106
166
if ( n instanceof ProjNode proj ) {
107
167
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 ();
109
169
return iadr ;
110
170
}
111
171
112
172
// ADDR ENCODING Op--- dst = src op src // Comment
113
173
// 1234 abcdefgh ld4 RAX = [Rbase + off] // Comment
114
- sb .hex4 (iadr );
115
- sb .p (" " );
174
+ sb .hex2 (iadr ).p (" " );
116
175
117
176
// 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 ,"" );
121
193
sb .p (" " );
122
194
123
195
// 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 (" " );
126
197
127
198
// General asm args
199
+ String isMultiOp = null ;
128
200
if ( n instanceof MachNode mach ) {
129
201
int old = sb .len ();
130
202
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
132
206
133
207
} else if ( !(n ._type instanceof SONTypeMem ) ) {
134
208
// Room for some inputs
@@ -149,14 +223,64 @@ static int doInst(int iadr, SB sb, CodeGen code, FunNode fun, CFGNode bb, Node n
149
223
150
224
sb .nl ();
151
225
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
+
152
261
// MultiNodes are immediately followed by projection(s)
153
262
if ( !(n instanceof CFGNode ) && n instanceof MultiNode ) {
154
263
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 );
157
266
}
158
267
}
159
268
160
269
return iadr ;
161
270
}
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
+
162
286
}
0 commit comments