add Outputable instance for OccIfaceEq
[ghc-hetmet.git] / driver / split / ghc-split.lprl
1 %************************************************************************
2 %*                                                                      *
3 \section[Driver-obj-splitting]{Splitting into many \tr{.o} files (for libraries)}
4 %*                                                                      *
5 %************************************************************************
6
7 \begin{code}
8 $TargetPlatform = $TARGETPLATFORM;
9
10 ($Pgm = $0) =~ s|.*/||;
11 $ifile      = $ARGV[0];
12 $Tmp_prefix = $ARGV[1];
13 $Output     = $ARGV[2];
14
15 &split_asm_file($ifile);
16
17 open(OUTPUT, "> $Output") ||  &tidy_up_and_die(1,"$Pgm: failed to open `$Output' (to write)\n");
18 print OUTPUT "$NoOfSplitFiles\n";
19 close(OUTPUT);
20
21 exit(0);
22 \end{code}
23
24
25 \begin{code}
26 sub split_asm_file {
27     local($asm_file) = @_;
28     my @pieces = ();
29
30     open(TMPI, "< $asm_file") || &tidy_up_and_die(1,"$Pgm: failed to open `$asm_file' (to read)\n");
31
32     &collectExports_hppa() if $TargetPlatform =~ /^hppa/;
33     &collectExports_mips() if $TargetPlatform =~ /^mips/;
34     &collectDyldStuff_darwin() if $TargetPlatform =~ /-apple-darwin/;
35
36     $octr = 0;  # output file counter
37     $* = 1;     # multi-line matches are OK
38
39     %LocalConstant = (); # we have to subvert C compiler's commoning-up of constants...
40
41     $s_stuff = &ReadTMPIUpToAMarker( '', $octr );
42     # that first stuff is a prologue for all .s outputs
43     $prologue_stuff = &process_asm_block ( $s_stuff );
44     # $_ already has some of the next stuff in it...
45
46 #   &tidy_up_and_die(1,"$Pgm: no split markers in .s file!\n")
47 #       if $prologue_stuff eq $s_stuff;
48
49     # lie about where this stuff came from
50     # Note the \Q: this ignores regex meta-chars in $Tmp_prefix.
51     $prologue_stuff =~ s/\Q"$Tmp_prefix.c"/"$ifile_root.hc"/g;
52
53     while ( $_ ne '' ) { # not EOF
54         $octr++;
55
56         # grab and de-mangle a section of the .s file...
57         $s_stuff = &ReadTMPIUpToAMarker ( $_, $octr );
58         $pieces[$octr] = &process_asm_block ( $s_stuff );
59     }
60
61     # Make sure that we still have some output when the input file is empty
62     if ($octr == 0) {
63         $octr = 1;
64         $pieces[$octr] = '';
65     }
66
67     $NoOfSplitFiles = $octr;
68
69     if ($pieces[$NoOfSplitFiles] =~ /(\n[ \t]*\.section[ \t]+\.note\.GNU-stack,[^\n]*\n)/) {
70         $note_gnu_stack = $1;
71         for $octr (1..($NoOfSplitFiles - 1)) {
72             $pieces[$octr] .= $note_gnu_stack;
73         }
74     }
75
76     for $octr (1..$NoOfSplitFiles) {
77         # output to a file of its own
78         # open a new output file...
79         $ofname = "${Tmp_prefix}__${octr}.s";
80         open(OUTF, "> $ofname") || die "$Pgm: can't open output file: $ofname\n";
81
82         print OUTF $prologue_stuff;
83         print OUTF $pieces[$octr];
84
85         close(OUTF)
86           || &tidy_up_and_die(1,"$Pgm:Failed writing ${Tmp_prefix}__${octr}.s\n");
87     }
88
89     close(TMPI) || &tidy_up_and_die(1,"Failed reading $asm_file\n");
90 }
91
92 sub collectExports_hppa { # Note: HP-PA only
93
94     %LocalExport = (); # NB: global table
95
96     while(<TMPI>) {
97         if (/^\s+\.EXPORT\s+([^,]+),.*\n/) {
98             local($label) = $1;
99             local($body)  = "\t.IMPORT $label";
100             if (/,DATA/) { 
101                 $body .= ",DATA\n"; 
102             } else { 
103                 $body .= ",CODE\n"; 
104             }
105             $label =~ s/\$/\\\$/g;
106             $LocalExport{$label} = $body;
107         }
108     }
109
110     seek(TMPI, 0, 0);
111 }
112
113 sub collectExports_mips { # Note: MIPS only
114     # (not really sure this is necessary [WDP 95/05])
115
116     $UNDEFINED_FUNS = ''; # NB: global table
117
118     while(<TMPI>) {
119         $UNDEFINED_FUNS .= $_ if /^\t\.globl\s+\S+ \.\S+\n/;
120         # just save 'em all
121     }
122
123     seek(TMPI, 0, 0);
124 }
125
126 sub collectDyldStuff_darwin {
127     local($chunk_label,$label,$cur_section,$section,$chunk,$alignment,$cur_alignment);
128     
129     %DyldChunks = (); # NB: global table
130     %DyldChunksDefined = (); # NB: global table
131         
132     $cur_section = '';
133     $section = '';
134     $label = '';
135     $chunk = '';
136     $alignment = '';
137     $cur_alignment = '';
138     
139     while ( 1 ) {
140         $_ = <TMPI>;
141         if ( $_ eq '' || (/^L(_.+)\$.+:/ && !(/^L(.*)\$stub_binder:/))) {
142             if ( $label ne '' ) {
143                 $DyldChunksDefined{$label} .= $section . $alignment . $chunk_label . $ chunk;
144                 if( $section =~ s/\.data/\.non_lazy_symbol_pointer/ ) {
145                     $chunk = "\t.indirect_symbol $label\n\t.long 0\n";
146                 }
147                 $DyldChunks{$label} .= $section . $alignment . $chunk_label . $chunk;
148                 print STDERR "### dyld chunk: $label\n$section$alignment$chunk\n###\n" if $Dump_asm_splitting_info;
149             }
150             last if ($_ eq '');
151                 
152             $chunk = '';
153             $chunk_label = $_;
154             $label = $1;
155             $section = $cur_section;
156             $alignment = $cur_alignment;
157             print STDERR "label: $label\n" if $Dump_asm_splitting_info;
158         } elsif ( /^\s*\.(symbol_stub|picsymbol_stub|lazy_symbol_pointer|non_lazy_symbol_pointer|data|section __IMPORT,.*|section __DATA, __la_sym_ptr(2|3),lazy_symbol_pointers)/ ) {
159             $cur_section = $_;
160             printf STDERR "section: $cur_section\n" if $Dump_asm_splitting_info;
161             $cur_alignment = ''
162         } elsif ( /^\s*\.section\s+__TEXT,__symbol_stub1,symbol_stubs,pure_instructions,\d+/ ) {
163             $cur_section = $_;
164             printf STDERR "section: $cur_section\n" if $Dump_asm_splitting_info;
165                 # always make sure we align things
166             $cur_alignment = '\t.align 2'
167         } elsif ( /^\s*\.align.*/ ) { 
168             $cur_alignment = $_;
169             printf STDERR "alignment: $cur_alignment\n" if $Dump_asm_splitting_info;
170         } else {
171             $chunk .= $_;
172         }
173     }
174     
175     seek(TMPI, 0, 0);
176 }
177
178 sub ReadTMPIUpToAMarker {
179     local($str, $count) = @_; # already read bits
180
181     
182     for ( $_ = <TMPI>; $_ ne '' && ! /_?__stg_split_marker/; $_ = <TMPI> ) {
183         $str .= $_;
184     }
185     # if not EOF, then creep forward until next "real" line
186     # (throwing everything away).
187     # that first "real" line will stay in $_.
188
189     # This loop is intended to pick up the body of the split_marker function
190     # Note that the assembler mangler will already have eliminated this code
191     # if it's been invoked (which it probably has).
192
193     while ($_ ne '' && (/_?__stg_split_marker/
194                      || /^L[^C].*:$/
195                      || /^\.stab/
196                      || /\t\.proc/
197                      || /\t\.stabd/
198                      || /\t\.even/
199                      || /\tunlk a6/
200                      || /^\t!#PROLOGUE/
201                      || /\t\.prologue/
202                      || /\t\.frame/
203                      # || /\t\.end/ NOT!  Let the split_marker regexp catch it
204                      # || /\t\.ent/ NOT!  Let the split_marker regexp catch it
205                      || /^\s+(save|retl?|restore|nop)/)) {
206         $_ = <TMPI>;
207     }
208
209     print STDERR "### BLOCK:$count:\n$str" if $Dump_asm_splitting_info;
210
211     # return str
212     $str =~ tr/\r//d if $TargetPlatform =~ /-mingw32$/; # in case Perl doesn't convert line endings
213     $str;
214 }
215 \end{code}
216
217 We must (a)~strip the marker off the block, (b)~record any literal C
218 constants that are defined here, and (c)~inject copies of any C constants
219 that are used-but-not-defined here.
220
221 \begin{code}
222 sub process_asm_block {
223     local($str) = @_;
224
225     return(&process_asm_block_darwin($str))
226                             if $TargetPlatform =~ /-apple-darwin/;
227     return(&process_asm_block_m68k($str))  if $TargetPlatform =~ /^m68k-/;
228     return(&process_asm_block_sparc($str)) if $TargetPlatform =~ /^sparc-/;
229     return(&process_asm_block_iX86($str))  if $TargetPlatform =~ /^i[34]86-/;
230     return(&process_asm_block_x86_64($str))  if $TargetPlatform =~ /^x86_64-/;
231     return(&process_asm_block_alpha($str)) if $TargetPlatform =~ /^alpha-/;
232     return(&process_asm_block_hppa($str))  if $TargetPlatform =~ /^hppa/;
233     return(&process_asm_block_mips($str))   if $TargetPlatform =~ /^mips-/;
234     return(&process_asm_block_powerpc_linux($str))
235                             if $TargetPlatform =~ /^powerpc-[^-]+-linux/;
236
237     # otherwise...
238     &tidy_up_and_die(1,"$Pgm: no process_asm_block for $TargetPlatform\n");
239 }
240
241 sub process_asm_block_sparc {
242     local($str) = @_;
243
244     # strip the marker
245     if ( $OptimiseC ) {
246         $str =~ s/_?__stg_split_marker.*:\n//;
247     } else {
248         $str =~ s/(\.text\n\t\.align .\n)\t\.global\s+.*_?__stg_split_marker.*\n\t\.proc.*\n/$1/;
249         $str =~ s/(\t\.align .\n)\t\.global\s+.*_?__stg_split_marker.*\n\t\.proc.*\n/$1/;
250     }
251
252     # make sure the *.hc filename gets saved; not just ghc*.c (temp name)
253     $str =~ s/^\.stabs "(ghc\d+\.c)"/.stabs "$ifile_root.hc"/g; # HACK HACK
254
255     # remove/record any literal constants defined here
256     while ( $str =~ /(\t\.align .\n\.?(L?LC\d+):\n(\t\.asci[iz].*\n)+)/ ) {
257         local($label) = $2;
258         local($body)  = $1;
259
260         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
261             if $LocalConstant{$label};
262
263         $LocalConstant{$label} = $body;
264         
265         $str =~ s/\t\.align .\n\.?LL?C\d+:\n(\t\.asci[iz].*\n)+//;
266     }
267
268     # inject definitions for any local constants now used herein
269     foreach $k (keys %LocalConstant) {
270         if ( $str =~ /\b$k\b/ ) {
271             $str = $LocalConstant{$k} . $str;
272         }
273     }
274
275    print STDERR "### STRIPPED BLOCK (sparc):\n$str" if $Dump_asm_splitting_info;
276
277    $str;
278 }
279
280 sub process_asm_block_m68k {
281     local($str) = @_;
282
283     # strip the marker
284
285     $str =~ s/(\.text\n\t\.even\n)\t\.globl\s+.*_?__stg_split_marker.*\n/$1/;
286     $str =~ s/(\t\.even\n)\t\.globl\s+.*_?__stg_split_marker.*\n/$1/;
287
288     # it seems prudent to stick on one of these:
289     $str = "\.text\n\t.even\n" . $str;
290
291     # remove/record any literal constants defined here
292     while ( $str =~ /((LC\d+):\n\t\.ascii.*\n)/ ) {
293         local($label) = $2;
294         local($body)  = $1;
295
296         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
297             if $LocalConstant{$label};
298
299         $LocalConstant{$label} = $body;
300         
301         $str =~ s/LC\d+:\n\t\.ascii.*\n//;
302     }
303
304     # inject definitions for any local constants now used herein
305     foreach $k (keys %LocalConstant) {
306         if ( $str =~ /\b$k\b/ ) {
307             $str = $LocalConstant{$k} . $str;
308         }
309     }
310
311    print STDERR "### STRIPPED BLOCK (m68k):\n$str" if $Dump_asm_splitting_info;
312
313    $str;
314 }
315
316 sub process_asm_block_alpha {
317     local($str) = @_;
318
319     # strip the marker
320     if ( $OptimiseC ) {
321         $str =~ s/_?__stg_split_marker.*:\n//;
322     } else {
323         $str =~ s/(\t\.align .\n)\t\.globl\s+.*_?__stg_split_marker.*\n\t\.ent.*\n/$1/;
324     }
325
326     # remove/record any literal constants defined here
327     while ( $str =~ /(\.rdata\n\t\.align \d\n)?(\$(C\d+):\n\t\..*\n)/ ) {
328         local($label) = $3;
329         local($body)  = $2;
330
331         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
332             if $LocalConstant{$label};
333
334         $LocalConstant{$label} = ".rdata\n\t.align 3\n" . $body . "\t.text\n";
335         
336         $str =~ s/(\.rdata\n\t\.align \d\n)?\$C\d+:\n\t\..*\n//;
337     }
338
339     # inject definitions for any local constants now used herein
340     foreach $k (keys %LocalConstant) {
341         if ( $str =~ /\$\b$k\b/ ) {
342             $str = $LocalConstant{$k} . $str;
343         }
344     }
345
346     # Slide the dummy direct return code into the vtbl .ent/.end block,
347     # to keep the label fixed if it's the last thing in a module, and
348     # to avoid having any anonymous text that the linker will complain about
349     $str =~ s/(\t\.end [A-Za-z0-9_]+)\n\t# nop/\tnop\n$1/g;
350
351     print STDERR "### STRIPPED BLOCK (alpha):\n$str" if $Dump_asm_splitting_info;
352
353     $str;
354 }
355
356 sub process_asm_block_iX86 {
357     local($str) = @_;
358
359     # strip the marker
360
361     $str =~ s/(\.text\n\t\.align .(,0x90)?\n)\.globl\s+.*_?__stg_split_marker.*\n/$1/;
362     $str =~ s/(\t\.align .(,0x90)?\n)\.globl\s+.*_?__stg_split_marker.*\n/$1/;
363
364     # it seems prudent to stick on one of these:
365     $str = "\.text\n\t.align 4\n" . $str;
366
367     # remove/record any literal constants defined here
368     # [perl made uglier to work around the perl 5.7/5.8 bug documented at
369     # http://bugs6.perl.org/rt2/Ticket/Display.html?id=1760 and illustrated
370     # by the seg fault of perl -e '("x\n" x 5000) =~ /(.*\n)+/'
371     # -- ccshan 2002-09-05]
372     while ( ($str =~ /(\.?(LC\d+):\n(\t\.(ascii|string).*\n|\s*\.byte.*\n){1,100})/ )) {
373         local($label) = $2;
374         local($body)  = $1;
375         local($prefix, $suffix, $*) = ($`, $', 0);
376
377         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
378             if $LocalConstant{$label};
379
380         while ( $suffix =~ /^((\t\.(ascii|string).*\n|\s*\.byte.*\n){1,100})/ ) {
381             $body .= $1;
382             $suffix = $';
383         }
384         $LocalConstant{$label} = $body;
385         $str = $prefix . $suffix;
386     }
387
388     # inject definitions for any local constants now used herein
389     foreach $k (keys %LocalConstant) {
390         if ( $str =~ /\b$k\b/ ) {
391             $str = $LocalConstant{$k} . $str;
392         }
393     }
394
395    print STDERR "### STRIPPED BLOCK (iX86):\n$str" if $Dump_asm_splitting_info;
396
397    $str;
398 }
399 \end{code}
400
401 \begin{code}
402 sub process_asm_block_x86_64 {
403     local($str) = @_;
404
405     # remove/record any literal constants defined here
406     # [perl made uglier to work around the perl 5.7/5.8 bug documented at
407     # http://bugs6.perl.org/rt2/Ticket/Display.html?id=1760 and illustrated
408     # by the seg fault of perl -e '("x\n" x 5000) =~ /(.*\n)+/'
409     # -- ccshan 2002-09-05]
410     while ( ($str =~ /(\.?(LC\d+):\n(\t\.(ascii|string).*\n|\s*\.byte.*\n){1,100})/ )) {
411         local($label) = $2;
412         local($body)  = $1;
413         local($prefix, $suffix, $*) = ($`, $', 0);
414
415         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
416             if $LocalConstant{$label};
417
418         while ( $suffix =~ /^((\t\.(ascii|string).*\n|\s*\.byte.*\n){1,100})/ ) {
419             $body .= $1;
420             $suffix = $';
421         }
422         $LocalConstant{$label} = $body;
423         $str = $prefix . $suffix;
424     }
425
426     # inject definitions for any local constants now used herein
427     foreach $k (keys %LocalConstant) {
428         if ( $str =~ /\b$k\b/ ) {
429             $str = $LocalConstant{$k} . $str;
430         }
431     }
432
433    print STDERR "### STRIPPED BLOCK (x86_64):\n$str" if $Dump_asm_splitting_info;
434
435    $str;
436 }
437 \end{code}
438
439 \begin{code}
440 sub process_asm_block_hppa {
441     local($str) = @_;
442
443     # strip the marker
444     $str =~ s/___stg_split_marker.*\n//;
445
446     # remove/record any imports defined here
447     while ( $str =~ /^(\s+\.IMPORT\s.*\n)/ ) {
448         $Imports .= $1;
449
450         $str =~ s/^\s+\.IMPORT.*\n//;
451     }
452
453     # remove/record any literal constants defined here
454     while ( $str =~ /^(\s+\.align.*\n(L\$C\d+)\n(\s.*\n)+); end literal\n/ ) {
455         local($label) = $2;
456         local($body)  = $1;
457         local($prefix) = $`;
458         local($suffix) = $';
459         $label =~ s/\$/\\\$/g;
460
461         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
462             if $LocalConstant{$label};
463
464         $LocalConstant{$label} = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$LIT\$\n\n" . $body;
465         
466         $str = $prefix . $suffix;
467     }
468
469     # inject definitions for any local constants now used herein
470     foreach $k (keys %LocalConstant) {
471         if ( $str =~ /\b$k\b/ ) {
472             $str = $LocalConstant{$k} . $str;
473         }
474     }
475
476     # inject required imports for local exports in other chunks
477     foreach $k (keys %LocalExport) {
478         if ( $str =~ /\b$k\b/ && ! /EXPORT\s+$k\b/ ) {
479             $str = $LocalExport{$k} . $str;
480         }
481     }
482
483     # inject collected imports
484
485     $str = $Imports . $str;
486
487     print STDERR "### STRIPPED BLOCK (hppa):\n$str" if $Dump_asm_splitting_info;
488
489     $str;
490 }
491 \end{code}
492
493 \begin{code}
494 sub process_asm_block_mips {
495     local($str) = @_;
496
497     # strip the marker
498     if ( $OptimiseC ) {
499         $str =~ s/_?__stg_split_marker.*:\n//;
500     } else {
501         $str =~ s/(\t\.align .\n)\t\.globl\s+.*_?__stg_split_marker.*\n\t\.ent.*\n/$1/;
502     }
503
504     # remove/record any literal constants defined here
505     while ( $str =~ /(\t\.rdata\n\t\.align \d\n)?(\$(LC\d+):\n(\t\.byte\t.*\n)+)/ ) {
506         local($label) = $3;
507         local($body)  = $2;
508
509         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
510             if $LocalConstant{$label};
511
512         $LocalConstant{$label} = "\t.rdata\n\t.align 2\n" . $body . "\t.text\n";
513         
514         $str =~ s/(\t\.rdata\n\t\.align \d\n)?\$LC\d+:\n(\t\.byte\t.*\n)+//;
515     }
516
517     # inject definitions for any local constants now used herein
518     foreach $k (keys %LocalConstant) {
519         if ( $str =~ /\$\b$k\b/ ) {
520             $str = $LocalConstant{$k} . $str;
521         }
522     }
523
524     # Slide the dummy direct return code into the vtbl .ent/.end block,
525     # to keep the label fixed if it's the last thing in a module, and
526     # to avoid having any anonymous text that the linker will complain about
527     $str =~ s/(\t\.end [A-Za-z0-9_]+)\n\t# nop/\tnop\n$1/g;
528
529     $str .= $UNDEFINED_FUNS; # pin on gratuitiously-large amount of info
530
531     print STDERR "### STRIPPED BLOCK (mips):\n$str" if $Dump_asm_splitting_info;
532
533     $str;
534 }
535 \end{code}
536
537 \begin{code}
538 # The logic for both Darwin/PowerPC and Darwin/x86 ends up being the same.
539
540 sub process_asm_block_darwin {
541     local($str) = @_;
542     local($dyld_stuff) = '';
543
544     # strip the marker
545     $str =~ s/___stg_split_marker.*\n//;
546
547     $str =~ s/L_.*\$.*:\n(.|\n)*//;
548
549     # remove/record any literal constants defined here
550     while ( $str =~ s/^(\s+.const.*\n\s+\.align.*\n(LC\d+):\n(\s\.(byte|short|long|fill|space|ascii).*\n)+)// ) {
551         local($label) = $2;
552         local($body)  = $1;
553
554         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
555             if $LocalConstant{$label};
556
557         $LocalConstant{$label} = $body;
558     }
559
560     # inject definitions for any local constants now used herein
561     foreach $k (keys %LocalConstant) {
562         if ( $str =~ /\b$k(\b|\[)/ ) {
563             $str = $LocalConstant{$k} . $str;
564         }
565     }
566     
567     foreach $k (keys %DyldChunks) {
568         if ( $str =~ /\bL$k\$/ ) {
569             if ( $str =~ /^$k:$/ ) {
570                 $dyld_stuff .= $DyldChunksDefined{$k};
571             } else {
572                 $dyld_stuff .= $DyldChunks{$k};
573             }
574         }
575     }
576
577     $str .= "\n" . $dyld_stuff;
578
579     print STDERR "### STRIPPED BLOCK (darwin):\n$str" if $Dump_asm_splitting_info;
580
581     $str;
582 }
583 \end{code}
584
585 \begin{code}
586 sub process_asm_block_powerpc_linux {
587     local($str) = @_;
588
589     # strip the marker
590     $str =~ s/__stg_split_marker.*\n//;
591
592     # remove/record any literal constants defined here
593     while ( $str =~ s/^(\s+.section\s+\.rodata\n\s+\.align.*\n(\.LC\d+):\n(\s\.(byte|short|long|quad|2byte|4byte|8byte|fill|space|ascii|string).*\n)+)// ) {
594         local($label) = $2;
595         local($body)  = $1;
596
597         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
598             if $LocalConstant{$label};
599
600         $LocalConstant{$label} = $body;
601     }
602
603     # inject definitions for any local constants now used herein
604     foreach $k (keys %LocalConstant) {
605         if ( $str =~ /[\s,]$k\b/ ) {
606             $str = $LocalConstant{$k} . $str;
607         }
608     }
609     
610     print STDERR "### STRIPPED BLOCK (powerpc linux):\n$str" if $Dump_asm_splitting_info;
611
612     $str;
613 }
614 \end{code}
615
616 \begin{code}
617 sub tidy_up_and_die {
618     local($return_val, $msg) = @_;
619     print STDERR $msg;
620     exit (($return_val == 0) ? 0 : 1);
621 }
622 \end{code}