1 %************************************************************************
3 \section[Driver-asm-fiddling]{Fiddling with assembler files (SPARC)}
5 %************************************************************************
10 Utterly stomp out C functions' prologues and epilogues; i.e., the
11 stuff to do with the C stack.
13 (SPARC) [Related] Utterly stomp out the changing of register windows.
15 Any other required tidying up.
20 local($in_asmf, $out_asmf) = @_;
22 # multi-line regexp matching:
27 open(INASM, "< $in_asmf")
28 || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n");
29 open(OUTASM,"> $out_asmf")
30 || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n");
32 # read whole file, divide into "chunks":
33 # record some info about what we've found...
35 @chk = (); # contents of the chunk
36 $numchks = 0; # number of them
37 @chkcat = (); # what category of thing in each chunk
38 @chksymb = (); # what symbol(base) is defined in this chunk
39 %slowchk = (); # ditto, its regular "slow" entry code
40 %fastchk = (); # ditto, fast entry code
41 %closurechk = (); # ditto, the (static) closure
42 %num_infos = (); # this symbol base has this many info tables (1-3)
43 %infochk = (); # given a symbol base, say what chunk its info tbl is in
44 %vectorchk = (); # ditto, return vector table
45 %directchk = (); # ditto, direct return code
51 next if /^\.stab.*___stg_split_marker/;
52 next if /^\.stab.*ghc.*c_ID/;
54 if ( /^\s+/ ) { # most common case first -- a simple line!
55 # duplicated from the bottom
59 } elsif ( /^_(ret_|djn_)/ ) {
64 } elsif ( /^_vtbl_([A-Za-z0-9_]+):$/ ) {
66 $chkcat[$i] = 'vector';
71 } elsif ( /^_([A-Za-z0-9_]+)DirectReturn:$/ ) {
73 $chkcat[$i] = 'direct';
78 } elsif ( /^_[A-Za-z0-9_]+_upd:$/ ) {
83 } elsif ( /^LC(\d+):$/ ) {
85 $chkcat[$i] = 'string';
88 } elsif ( /^___stg_split_marker(\d+):$/ ) {
90 $chkcat[$i] = 'splitmarker';
93 } elsif ( /^_([A-Za-z0-9_]+)_info:$/ ) {
96 $chkcat[$i] = 'infotbl';
101 } elsif ( /^_([A-Za-z0-9_]+)_entry:$/ ) {
103 $chkcat[$i] = 'slow';
108 } elsif ( /^_([A-Za-z0-9_]+)_fast\d+:$/ ) {
110 $chkcat[$i] = 'fast';
115 } elsif ( /^_([A-Za-z0-9_]+)_closure:$/ ) {
117 $chkcat[$i] = 'closure';
120 $closurechk{$1} = $i;
122 } elsif ( /^_ghc.*c_ID:/ ) {
124 $chkcat[$i] = 'consist';
126 } elsif ( /^(___gnu_compiled_c|gcc2_compiled\.):/ ) {
129 } elsif ( /^_ErrorIO_call_count:/ # HACK!!!!
130 || /^_[A-Za-z0-9_]+\.\d+:$/
131 || /^_.*_CAT:/ # PROF: _entryname_CAT
132 || /^_CC_.*_struct:/ # PROF: _CC_ccident_struct
133 || /^_.*_done:/ # PROF: _module_done
134 || /^__module_registered:/ # PROF: _module_registered
137 $chkcat[$i] = 'data';
140 } elsif ( /^_[A-Za-z0-9_]/ ) {
143 print STDERR "Funny global thing?: $_"
144 unless $KNOWN_FUNNY_THING{$thing}
145 || /^__(PRIn|PRStart).*:/ # pointer reversal GC routines
146 || /^_CC_.*:/ # PROF: _CC_ccident
147 || /^__reg.*:/; # PROF: __reg<module>
149 $chkcat[$i] = 'misc';
152 } else { # simple line (duplicated at the top)
157 $numchks = $#chk + 1;
159 # the division into chunks is imperfect;
160 # we throw some things over the fence into the next
163 # also, there are things we would like to know
164 # about the whole module before we start spitting
167 # NB: we start meddling at chunk 1, not chunk 0
169 for ($i = 1; $i < $numchks; $i++) {
170 $c = $chk[$i]; # convenience copy
172 # print STDERR "\nCHK $i (BEFORE):\n", $c;
174 # toss all reg-window stuff (save/restore/ret[l] s):
175 $c =~ s/^\t(save .*|restore|ret|retl)\n//g;
176 # throw away PROLOGUE comments
177 $c =~ s/^\t!#PROLOGUE# 0\n\t!#PROLOGUE# 1\n//;
179 # pin a funny end-thing on (for easier matching):
180 $c .= 'FUNNY#END#THING';
182 # pick some end-things and move them to the next chunk
184 while ( $c =~ /^(\s+\.align\s+\d+\n|\s+\.proc\s+\d+\n|\s+\.global\s+\S+\n|\.text\n|\.data\n|\.stab.*\n)FUNNY#END#THING/ ) {
187 if ( $to_move =~ /\.(global|proc|stab)/ && $i < ($numchks - 1) ) {
188 $chk[$i + 1] = $to_move . $chk[$i + 1];
189 # otherwise they're tossed
192 $c =~ s/^.*\nFUNNY#END#THING/FUNNY#END#THING/;
195 $c =~ s/FUNNY#END#THING//;
196 $chk[$i] = $c; # update w/ convenience copy
198 # print STDERR "\nCHK $i (AFTER):\n", $c;
201 # print out all the literal strings first
202 for ($i = 0; $i < $numchks; $i++) {
203 if ( $chkcat[$i] eq 'string' ) {
204 print OUTASM "\.text\n\t\.align 8\n";
205 print OUTASM $chk[$i];
207 $chkcat[$i] = 'DONE ALREADY';
211 for ($i = 0; $i < $numchks; $i++) {
212 # print STDERR "$i: cat $chkcat[$i], symb $chksymb[$i]\n";
214 next if $chkcat[$i] eq 'DONE ALREADY';
216 if ( $chkcat[$i] eq 'misc' ) {
217 print OUTASM "\.text\n\t\.align 4\n";
218 print OUTASM $chk[$i];
220 } elsif ( $chkcat[$i] eq 'data' ) {
221 print OUTASM "\.data\n\t\.align 8\n";
222 print OUTASM $chk[$i];
224 } elsif ( $chkcat[$i] eq 'consist' ) {
225 if ( $chk[$i] =~ /\.ascii.*\)(hsc|cc) (.*)\\11"\n\t\.ascii\s+"(.*)\\0"/ ) {
226 local($consist) = "$1.$2.$3";
228 $consist =~ s/\//./g;
230 $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly?
231 print OUTASM "\.text\n$consist:\n";
233 print STDERR "Couldn't grok consistency: ", $chk[$i];
236 } elsif ( $chkcat[$i] eq 'splitmarker' ) {
237 # we can just re-constitute this one...
238 print OUTASM "___stg_split_marker",$chksymb[$i],":\n";
240 } elsif ( $chkcat[$i] eq 'closure'
241 || $chkcat[$i] eq 'infotbl'
242 || $chkcat[$i] eq 'slow'
243 || $chkcat[$i] eq 'fast' ) { # do them in that order
244 $symb = $chksymb[$i];
246 # print STDERR "$i: cat $chkcat[$i], symb $symb ",defined($closurechk{$symb}),":",defined($infochk{$symb}),":",defined($slowchk{$symb}),":",defined($fastchk{$symb}),"\n";
249 if ( defined($closurechk{$symb}) ) {
250 print OUTASM "\.data\n\t\.align 4\n";
251 print OUTASM $chk[$closurechk{$symb}];
252 $chkcat[$closurechk{$symb}] = 'DONE ALREADY';
256 if ( defined($infochk{$symb}) ) {
258 print OUTASM "\.text\n\t\.align 4\n";
259 print OUTASM &rev_tbl($symb, $chk[$infochk{$symb}], 1);
260 # entry code will follow, here!
262 $chkcat[$infochk{$symb}] = 'DONE ALREADY';
266 if ( defined($slowchk{$symb}) ) {
268 # teach it to drop through to the fast entry point:
269 $c = $chk[$slowchk{$symb}];
270 $c =~ s/^\tcall _${symb}_fast\d+,.*\n\tnop\n//;
271 $c =~ s/^\tcall _${symb}_fast\d+,.*\n(\t[a-z].*\n)/\1/;
273 print STDERR "still has jump to fast entry point:\n$c"
274 if $c =~ /_${symb}_fast/;
276 print OUTASM "\.text\n\t\.align 4\n";
278 $chkcat[$slowchk{$symb}] = 'DONE ALREADY';
282 if ( defined($fastchk{$symb}) ) {
283 print OUTASM "\.text\n\t\.align 4\n";
284 print OUTASM $chk[$fastchk{$symb}];
285 $chkcat[$fastchk{$symb}] = 'DONE ALREADY';
288 } elsif ( $chkcat[$i] eq 'vector'
289 || $chkcat[$i] eq 'direct' ) { # do them in that order
290 $symb = $chksymb[$i];
293 if ( defined($vectorchk{$symb}) ) {
294 print OUTASM "\.text\n\t\.align 4\n";
295 print OUTASM &rev_tbl($symb, $chk[$vectorchk{$symb}], 0);
296 # direct return code will be put here!
297 $chkcat[$vectorchk{$symb}] = 'DONE ALREADY';
301 if ( defined($directchk{$symb}) ) {
302 print OUTASM "\.text\n\t\.align 4\n";
303 print OUTASM $chk[$directchk{$symb}];
304 $chkcat[$directchk{$symb}] = 'DONE ALREADY';
308 &tidy_up_and_die(1,"$Pgm: unknown chkcat (ghc-asm SPARC)\n$chkcat[$i]\n$chk[$i]\n");
313 close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n");
314 close(INASM) || &tidy_up_and_die(1,"Failed reading from $in_asmf\n");
319 sub init_FUNNY_THINGS {
320 %KNOWN_FUNNY_THING = (
321 '_CheckHeapCode:', 1,
322 '_CommonUnderflow:', 1,
324 '_EnterNodeCode:', 1,
325 '_ErrorIO_call_count:', 1,
326 '_ErrorIO_innards:', 1,
336 '_PrimUnderflow:', 1,
337 '_StackUnderflowEnterNode:', 1,
339 '_UnderflowVect0:', 1,
340 '_UnderflowVect1:', 1,
341 '_UnderflowVect2:', 1,
342 '_UnderflowVect3:', 1,
343 '_UnderflowVect4:', 1,
344 '_UnderflowVect5:', 1,
345 '_UnderflowVect6:', 1,
346 '_UnderflowVect7:', 1,
349 '_WorldStateToken:', 1,
350 '__Enter_Internal:', 1,
351 '__PRMarking_MarkNextAStack:', 1,
352 '__PRMarking_MarkNextBStack:', 1,
353 '__PRMarking_MarkNextCAF:', 1,
354 '__PRMarking_MarkNextGA:', 1,
355 '__PRMarking_MarkNextRoot:', 1,
356 '__PRMarking_MarkNextSpark:', 1,
357 '__Scavenge_Forward_Ref:', 1,
358 '___std_entry_error__:', 1,
359 '__startMarkWorld:', 1,
361 '_startCcRegisteringWorld:', 1,
362 '_startEnterFloat:', 1,
363 '_startEnterInt:', 1,
364 '_startPerformIO:', 1,
365 '_startStgWorld:', 1,
371 The following table reversal is used for both info tables and return
372 vectors. In both cases, we remove the first entry from the table,
373 reverse the table, put the label at the end, and paste some code
374 (that which is normally referred to by the first entry in the table)
375 right after the table itself. (The code pasting is done elsewhere.)
379 local($symb, $tbl, $discard1) = @_;
385 local(@lines) = split(/\n/, $tbl);
388 for ($i = 0; $i <= $#lines && $lines[$i] !~ /^\t\.word\s+/; $i++) {
389 $label .= $lines[$i] . "\n",
390 next if $lines[$i] =~ /^[A-Za-z0-9_]+:$/
391 || $lines[$i] =~ /^\t\.global/;
393 $before .= $lines[$i] . "\n"; # otherwise...
396 for ( ; $i <= $#lines && $lines[$i] =~ /^\t\.word\s+/; $i++) {
397 push(@words, $lines[$i]);
399 # now throw away the first word (entry code):
400 shift(@words) if $discard1;
402 for (; $i <= $#lines; $i++) {
403 $after .= $lines[$i] . "\n";
406 $tbl = $before . join("\n", (reverse @words)) . "\n" . $label . $after;
408 # print STDERR "before=$before\n";
409 # print STDERR "label=$label\n";
410 # print STDERR "words=",(reverse @words),"\n";
411 # print STDERR "after=$after\n";
417 %************************************************************************
419 \subsection[Driver-asm-info]{Collect interesting (static) info from an assembler file}
421 %************************************************************************
423 How many times is each asm instruction used?
426 %AsmInsn = (); # init
428 sub dump_asm_insn_counts {
431 open(INASM, "< $asmf") || &tidy_up_and_die(1,"$Pgm: failed to open `$asmf' (to read)\n");
433 if ( /^\t([a-z][a-z0-9]+)\b/ ) {
437 close(INASM) || &tidy_up_and_die(1,"Failed reading from $asmf\n");
439 # OK, now print what we collected (to stderr)
440 foreach $i (sort (keys %AsmInsn)) {
441 print STDERR "INSN:: $i\t",$AsmInsn{$i},"\n";
446 How many times is each ``global variable'' used in a \tr{sethi}
447 instruction (SPARC)? This can give some guidance about what should be
448 put in machine registers...
451 %SethiGlobal = (); # init
453 sub dump_asm_globals_info {
458 open(INASM, "< $asmf") || &tidy_up_and_die(1,"$Pgm: failed to open `$asmf' (to read)\n");
460 if ( /^\tsethi \%hi\(_([_A-Za-z0-9]+)/ ) {
462 next if $globl =~ /(ds|fail|stg|tpl|vtbl)_[0-9]+/;
464 $SethiGlobal{$globl} ++;
467 close(INASM) || &tidy_up_and_die(1,"Failed reading from $asmf\n");
469 # OK, now print what we collected (to stderr)
470 foreach $i (sort (keys %SethiGlobal)) {
471 print STDERR "GLOBAL:: $i\t",$SethiGlobal{$i},"\n";
475 # make "require"r happy...