[project @ 2000-06-13 15:35:29 by simonmar]
[ghc-hetmet.git] / ghc / 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 sub split_asm_file {
9     local($asm_file) = @_;
10
11     open(TMPI, "< $asm_file") || &tidy_up_and_die(1,"$Pgm: failed to open `$asm_file' (to read)\n");
12
13     &collectExports_hppa() if $TargetPlatform =~ /^hppa/;
14     &collectExports_mips() if $TargetPlatform =~ /^mips/;
15
16     $octr = 0;  # output file counter
17     $* = 1;     # multi-line matches are OK
18
19     %LocalConstant = (); # we have to subvert C compiler's commoning-up of constants...
20
21     $s_stuff = &ReadTMPIUpToAMarker( '', $octr );
22     # that first stuff is a prologue for all .s outputs
23     $prologue_stuff = &process_asm_block ( $s_stuff );
24     # $_ already has some of the next stuff in it...
25
26 #   &tidy_up_and_die(1,"$Pgm: no split markers in .s file!\n")
27 #       if $prologue_stuff eq $s_stuff;
28
29     # lie about where this stuff came from
30     $prologue_stuff =~ s|"/tmp/ghc\d+\.c"|"$ifile_root\.hc"|g;
31
32     while ( $_ ne '' ) { # not EOF
33         $octr++;
34
35         # grab and de-mangle a section of the .s file...
36         $s_stuff = &ReadTMPIUpToAMarker ( $_, $octr );
37         $this_piece = &process_asm_block ( $s_stuff );
38
39         # output to a file of its own
40         # open a new output file...
41         $ofname = "${Tmp_prefix}__${octr}.s";
42         open(OUTF, "> $ofname") || die "$Pgm: can't open output file: $ofname\n";
43
44         print OUTF $prologue_stuff;
45         print OUTF $this_piece;
46
47         close(OUTF)
48           || &tidy_up_and_die(1,"$Pgm:Failed writing ${Tmp_prefix}__${octr}.s\n");
49     }
50
51     $NoOfSplitFiles = $octr;
52
53     close(TMPI) || &tidy_up_and_die(1,"Failed reading $asm_file\n");
54 }
55
56 sub collectExports_hppa { # Note: HP-PA only
57
58     %LocalExport = (); # NB: global table
59
60     while(<TMPI>) {
61         if (/^\s+\.EXPORT\s+([^,]+),.*\n/) {
62             local($label) = $1;
63             local($body)  = "\t.IMPORT $label";
64             if (/,DATA/) { 
65                 $body .= ",DATA\n"; 
66             } else { 
67                 $body .= ",CODE\n"; 
68             }
69             $label =~ s/\$/\\\$/g;
70             $LocalExport{$label} = $body;
71         }
72     }
73
74     seek(TMPI, 0, 0);
75 }
76
77 sub collectExports_mips { # Note: MIPS only
78     # (not really sure this is necessary [WDP 95/05])
79
80     $UNDEFINED_FUNS = ''; # NB: global table
81
82     while(<TMPI>) {
83         $UNDEFINED_FUNS .= $_ if /^\t\.globl\s+\S+ \.\S+\n/;
84         # just save 'em all
85     }
86
87     seek(TMPI, 0, 0);
88 }
89
90 sub ReadTMPIUpToAMarker {
91     local($str, $count) = @_; # already read bits
92
93     
94     for ( $_ = <TMPI>; $_ ne '' && ! /_?__stg_split_marker/; $_ = <TMPI> ) {
95         $str .= $_;
96     }
97     # if not EOF, then creep forward until next "real" line
98     # (throwing everything away).
99     # that first "real" line will stay in $_.
100
101     # This loop is intended to pick up the body of the split_marker function
102     # Note that the assembler mangler will already have eliminated this code
103     # if it's been invoked (which it probably has).
104
105     while ($_ ne '' && (/_?__stg_split_marker/
106                      || /^L[^C].*:$/
107                      || /^\.stab/
108                      || /\t\.proc/
109                      || /\t\.stabd/
110                      || /\t\.even/
111                      || /\tunlk a6/
112                      || /^\t!#PROLOGUE/
113                      || /\t\.prologue/
114                      || /\t\.frame/
115                      # || /\t\.end/ NOT!  Let the split_marker regexp catch it
116                      # || /\t\.ent/ NOT!  Let the split_marker regexp catch it
117                      || /^\s+(save|retl?|restore|nop)/)) {
118         $_ = <TMPI>;
119     }
120
121     print STDERR "### BLOCK:$count:\n$str" if $Dump_asm_splitting_info;
122
123     # return str
124     $str;
125 }
126 \end{code}
127
128 We must (a)~strip the marker off the block, (b)~record any literal C
129 constants that are defined here, and (c)~inject copies of any C constants
130 that are used-but-not-defined here.
131
132 \begin{code}
133 sub process_asm_block {
134     local($str) = @_;
135
136     return(&process_asm_block_m68k($str))  if $TargetPlatform =~ /^m68k-/;
137     return(&process_asm_block_sparc($str)) if $TargetPlatform =~ /^sparc-/;
138     return(&process_asm_block_iX86($str))  if $TargetPlatform =~ /^i[34]86-/;
139     return(&process_asm_block_alpha($str)) if $TargetPlatform =~ /^alpha-/;
140     return(&process_asm_block_hppa($str))  if $TargetPlatform =~ /^hppa/;
141     return(&process_asm_block_mips($str))   if $TargetPlatform =~ /^mips-/;
142     return(&process_asm_block_powerpc($str))   if $TargetPlatform =~ /^powerpc-|^rs6000-/;
143
144     # otherwise...
145     &tidy_up_and_die(1,"$Pgm: no process_asm_block for $TargetPlatform\n");
146 }
147
148 sub process_asm_block_sparc {
149     local($str) = @_;
150
151     # strip the marker
152     if ( $OptimiseC ) {
153         $str =~ s/_?__stg_split_marker.*:\n//;
154     } else {
155         $str =~ s/(\.text\n\t\.align .\n)\t\.global\s+.*_?__stg_split_marker.*\n\t\.proc.*\n/$1/;
156         $str =~ s/(\t\.align .\n)\t\.global\s+.*_?__stg_split_marker.*\n\t\.proc.*\n/$1/;
157     }
158
159     # make sure the *.hc filename gets saved; not just ghc*.c (temp name)
160     $str =~ s/^\.stabs "(ghc\d+\.c)"/.stabs "$ifile_root.hc"/g; # HACK HACK
161
162     # remove/record any literal constants defined here
163     while ( $str =~ /(\t\.align .\n\.?(L?LC\d+):\n(\t\.asci[iz].*\n)+)/ ) {
164         local($label) = $2;
165         local($body)  = $1;
166
167         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
168             if $LocalConstant{$label};
169
170         $LocalConstant{$label} = $body;
171         
172         $str =~ s/\t\.align .\n\.?LL?C\d+:\n(\t\.asci[iz].*\n)+//;
173     }
174
175     # inject definitions for any local constants now used herein
176     foreach $k (keys %LocalConstant) {
177         if ( $str =~ /\b$k\b/ ) {
178             $str = $LocalConstant{$k} . $str;
179         }
180     }
181
182    print STDERR "### STRIPPED BLOCK (sparc):\n$str" if $Dump_asm_splitting_info;
183
184    $str;
185 }
186
187 sub process_asm_block_m68k {
188     local($str) = @_;
189
190     # strip the marker
191
192     $str =~ s/(\.text\n\t\.even\n)\t\.globl\s+.*_?__stg_split_marker.*\n/$1/;
193     $str =~ s/(\t\.even\n)\t\.globl\s+.*_?__stg_split_marker.*\n/$1/;
194
195     # it seems prudent to stick on one of these:
196     $str = "\.text\n\t.even\n" . $str;
197
198     # remove/record any literal constants defined here
199     while ( $str =~ /((LC\d+):\n\t\.ascii.*\n)/ ) {
200         local($label) = $2;
201         local($body)  = $1;
202
203         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
204             if $LocalConstant{$label};
205
206         $LocalConstant{$label} = $body;
207         
208         $str =~ s/LC\d+:\n\t\.ascii.*\n//;
209     }
210
211     # inject definitions for any local constants now used herein
212     foreach $k (keys %LocalConstant) {
213         if ( $str =~ /\b$k\b/ ) {
214             $str = $LocalConstant{$k} . $str;
215         }
216     }
217
218    print STDERR "### STRIPPED BLOCK (m68k):\n$str" if $Dump_asm_splitting_info;
219
220    $str;
221 }
222
223 sub process_asm_block_alpha {
224     local($str) = @_;
225
226     # strip the marker
227     if ( $OptimiseC ) {
228         $str =~ s/_?__stg_split_marker.*:\n//;
229     } else {
230         $str =~ s/(\t\.align .\n)\t\.globl\s+.*_?__stg_split_marker.*\n\t\.ent.*\n/$1/;
231     }
232
233     # remove/record any literal constants defined here
234     while ( $str =~ /(\.rdata\n\t\.align \d\n)?(\$(C\d+):\n\t\..*\n)/ ) {
235         local($label) = $3;
236         local($body)  = $2;
237
238         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
239             if $LocalConstant{$label};
240
241         $LocalConstant{$label} = ".rdata\n\t.align 3\n" . $body . "\t.text\n";
242         
243         $str =~ s/(\.rdata\n\t\.align \d\n)?\$C\d+:\n\t\..*\n//;
244     }
245
246     # inject definitions for any local constants now used herein
247     foreach $k (keys %LocalConstant) {
248         if ( $str =~ /\$\b$k\b/ ) {
249             $str = $LocalConstant{$k} . $str;
250         }
251     }
252
253     # Slide the dummy direct return code into the vtbl .ent/.end block,
254     # to keep the label fixed if it's the last thing in a module, and
255     # to avoid having any anonymous text that the linker will complain about
256     $str =~ s/(\t\.end [A-Za-z0-9_]+)\n\t# nop/\tnop\n$1/g;
257
258     print STDERR "### STRIPPED BLOCK (alpha):\n$str" if $Dump_asm_splitting_info;
259
260     $str;
261 }
262
263 sub process_asm_block_iX86 {
264     local($str) = @_;
265
266     # strip the marker
267
268     $str =~ s/(\.text\n\t\.align .(,0x90)?\n)\.globl\s+.*_?__stg_split_marker.*\n/$1/;
269     $str =~ s/(\t\.align .(,0x90)?\n)\.globl\s+.*_?__stg_split_marker.*\n/$1/;
270
271     # it seems prudent to stick on one of these:
272     $str = "\.text\n\t.align 4\n" . $str;
273
274     # remove/record any literal constants defined here
275     while ( ($str =~ /(\.?(LC\d+):\n\t\.(ascii|string).*\n)/ )) {
276         local($label) = $2;
277         local($body)  = $1;
278
279         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
280             if $LocalConstant{$label};
281
282         $LocalConstant{$label} = $body;
283         
284         $str =~ s/\.?LC\d+:\n\t\.(ascii|string).*\n//;
285     }
286
287     # inject definitions for any local constants now used herein
288     foreach $k (keys %LocalConstant) {
289         if ( $str =~ /\b$k\b/ ) {
290             $str = $LocalConstant{$k} . $str;
291         }
292     }
293
294    print STDERR "### STRIPPED BLOCK (iX86):\n$str" if $Dump_asm_splitting_info;
295
296    $str;
297 }
298 \end{code}
299
300 \begin{code}
301 sub process_asm_block_hppa {
302     local($str) = @_;
303
304     # strip the marker
305     $str =~ s/___stg_split_marker.*\n//;
306
307     # remove/record any imports defined here
308     while ( $str =~ /^(\s+\.IMPORT\s.*\n)/ ) {
309         $Imports .= $1;
310
311         $str =~ s/^\s+\.IMPORT.*\n//;
312     }
313
314     # remove/record any literal constants defined here
315     while ( $str =~ /^(\s+\.align.*\n(L\$C\d+)\n(\s.*\n)+); end literal\n/ ) {
316         local($label) = $2;
317         local($body)  = $1;
318         $label =~ s/\$/\\\$/g;
319
320         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
321             if $LocalConstant{$label};
322
323         $LocalConstant{$label} = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$LIT\$\n\n" . $body;
324         
325         $str =~ s/^\s+\.SPACE \$TEXT\$\n\s+\.SUBSPA \$LIT\$\s+\.align.*\nL\$C\d+\n(\s.*\n)+; end literal\n//;
326     }
327
328     # inject definitions for any local constants now used herein
329     foreach $k (keys %LocalConstant) {
330         if ( $str =~ /\b$k\b/ ) {
331             $str = $LocalConstant{$k} . $str;
332         }
333     }
334
335     # inject required imports for local exports in other chunks
336     foreach $k (keys %LocalExport) {
337         if ( $str =~ /\b$k\b/ && ! /EXPORT\s+$k\b/ ) {
338             $str = $LocalExport{$k} . $str;
339         }
340     }
341
342     # inject collected imports
343
344     $str = $Imports . $str;
345
346     print STDERR "### STRIPPED BLOCK (hppa):\n$str" if $Dump_asm_splitting_info;
347
348     $str;
349 }
350 \end{code}
351
352 \begin{code}
353 sub process_asm_block_mips {
354     local($str) = @_;
355
356     # strip the marker
357     if ( $OptimiseC ) {
358         $str =~ s/_?__stg_split_marker.*:\n//;
359     } else {
360         $str =~ s/(\t\.align .\n)\t\.globl\s+.*_?__stg_split_marker.*\n\t\.ent.*\n/$1/;
361     }
362
363     # remove/record any literal constants defined here
364     while ( $str =~ /(\t\.rdata\n\t\.align \d\n)?(\$(LC\d+):\n(\t\.byte\t.*\n)+)/ ) {
365         local($label) = $3;
366         local($body)  = $2;
367
368         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
369             if $LocalConstant{$label};
370
371         $LocalConstant{$label} = "\t.rdata\n\t.align 2\n" . $body . "\t.text\n";
372         
373         $str =~ s/(\t\.rdata\n\t\.align \d\n)?\$LC\d+:\n(\t\.byte\t.*\n)+//;
374     }
375
376     # inject definitions for any local constants now used herein
377     foreach $k (keys %LocalConstant) {
378         if ( $str =~ /\$\b$k\b/ ) {
379             $str = $LocalConstant{$k} . $str;
380         }
381     }
382
383     # Slide the dummy direct return code into the vtbl .ent/.end block,
384     # to keep the label fixed if it's the last thing in a module, and
385     # to avoid having any anonymous text that the linker will complain about
386     $str =~ s/(\t\.end [A-Za-z0-9_]+)\n\t# nop/\tnop\n$1/g;
387
388     $str .= $UNDEFINED_FUNS; # pin on gratuitiously-large amount of info
389
390     print STDERR "### STRIPPED BLOCK (mips):\n$str" if $Dump_asm_splitting_info;
391
392     $str;
393 }
394 \end{code}
395
396 \begin{code}
397 sub process_asm_block_powerpc {
398     local($str) = @_;
399
400     # strip the marker
401     $str =~ s/___stg_split_marker.*\n//;
402     $str =~ s/___stg_split_marker.*\n//; # yes, twice.
403
404     # remove/record any literal constants defined here
405     while ( $str =~ /^(.csect .data[RW]\n\s+\.align.*\n(LC\.\.\d+):\n(\s\.byte .*\n)+)/ ) {
406         local($label) = $2;
407         local($body)  = $1;
408
409         &tidy_up_and_die(1,"Local constant label $label already defined!\n")
410             if $LocalConstant{$label};
411
412         $LocalConstant{$label} = $body;
413         
414         $str =~ s/^.csect .data[RW]\n\s+\.align.*\nLC\.\.\d+:\n(\s\.byte .*\n)+//;
415     }
416
417     # inject definitions for any local constants now used herein
418     foreach $k (keys %LocalConstant) {
419         if ( $str =~ /\b$k(\b|\[)/ ) {
420             $str = $LocalConstant{$k} . $str;
421         }
422     }
423
424     print STDERR "### STRIPPED BLOCK (powerpc/rs6000):\n$str" if $Dump_asm_splitting_info;
425
426     $str = ".toc\n" . $str;
427
428     $str;
429 }
430 \end{code}
431
432 \begin{code}
433 # make "require"r happy...
434 1;
435 \end{code}
436