f597b37863d959bb828da52daff0bc13097751f5
[ghc-hetmet.git] / ghc / driver / mangler / ghc-asm.lprl
1 %************************************************************************
2 %*                                                                      *
3 \section[Driver-asm-fiddling]{Fiddling with assembler files}
4 %*                                                                      *
5 %************************************************************************
6
7 Tasks:
8 \begin{itemize}
9 \item
10 Utterly stomp out C functions' prologues and epilogues; i.e., the
11 stuff to do with the C stack.
12 \item
13 Any other required tidying up.
14 \end{itemize}
15
16 HPPA specific notes:
17 \begin{itemize}
18 \item
19 The HP linker is very picky about symbols being in the appropriate
20 space (code vs. data).  When we mangle the threaded code to put the
21 info tables just prior to the code, they wind up in code space
22 rather than data space.  This means that references to *_info from
23 un-mangled parts of the RTS (e.g. unthreaded GC code) get
24 unresolved symbols.  Solution:  mini-mangler for .c files on HP.  I
25 think this should really be triggered in the driver by a new -rts
26 option, so that user code doesn't get mangled inappropriately.
27 \item
28 With reversed tables, jumps are to the _info label rather than to
29 the _entry label.  The _info label is just an address in code
30 space, rather than an entry point with the descriptive blob we
31 talked about yesterday.  As a result, you can't use the call-style
32 JMP_ macro.  However, some JMP_ macros take _info labels as targets
33 and some take code entry points within the RTS.  The latter won't
34 work with the goto-style JMP_ macro.  Sigh.  Solution: Use the goto
35 style JMP_ macro, and mangle some more assembly, changing all
36 "RP'literal" and "LP'literal" references to "R'literal" and
37 "L'literal," so that you get the real address of the code, rather
38 than the descriptive blob.  Also change all ".word P%literal"
39 entries in info tables and vector tables to just ".word literal,"
40 for the same reason.  Advantage: No more ridiculous call sequences.
41 \end{itemize}
42
43 %************************************************************************
44 %*                                                                      *
45 \subsection{Constants for various architectures}
46 %*                                                                      *
47 %************************************************************************
48
49 \begin{code}
50 sub init_TARGET_STUFF {
51
52     #--------------------------------------------------------#
53     if ( $TargetPlatform =~ /^alpha-.*-.*/ ) {
54
55     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
56     $T_US           = ''; # _ if symbols have an underscore on the front
57     $T_DO_GC        = 'PerformGC_wrapper';
58     $T_PRE_APP      = 'DONT THINK THIS APPLIES'; # regexp that says what comes before APP/NO_APP
59     $T_CONST_LBL    = '^\$C(\d+):$'; # regexp for what such a lbl looks like
60     $T_POST_LBL     = ':';
61
62     $T_MOVE_DIRVS   = '^(\s*(\.align\s+\d+|\.(globl|ent)\s+\S+|\#.*|\.(file|loc)\s+\S+\s+\S+|\.text|\.r?data)\n)';
63     $T_COPY_DIRVS   = '^\s*(\#|\.(file|globl|ent|loc))';
64
65     $T_hsc_cc_PAT   = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"';
66     $T_DOT_WORD     = '\.quad';
67     $T_DOT_GLOBAL   = '^\t\.globl';
68     $T_HDR_literal  = "\.rdata\n\t\.align 3\n";
69     $T_HDR_misc     = "\.text\n\t\.align 3\n";
70     $T_HDR_data     = "\.data\n\t\.align 3\n";
71     $T_HDR_consist  = "\.text\n";
72     $T_HDR_closure  = "\.data\n\t\.align 3\n";
73     $T_HDR_info     = "\.text\n\t\.align 3\n";
74     $T_HDR_entry    = "\.text\n\t\.align 3\n";
75     $T_HDR_fast     = "\.text\n\t\.align 3\n";
76     $T_HDR_vector   = "\.text\n\t\.align 3\n";
77     $T_HDR_direct   = "\.text\n\t\.align 3\n";
78
79     #--------------------------------------------------------#
80     } elsif ( $TargetPlatform =~ /^hppa/ ) {
81
82     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
83     $T_US           = ''; # _ if symbols have an underscore on the front
84     $T_DO_GC        = 'PerformGC_wrapper';
85     $T_PRE_APP      = 'DONT THINK THIS APPLIES'; # regexp that says what comes before APP/NO_APP
86     $T_CONST_LBL    = '^L\$C(\d+)$'; # regexp for what such a lbl looks like
87     $T_POST_LBL     = '';
88
89     $T_MOVE_DIRVS   = '^((\s+\.(IMPORT|EXPORT|PARAM).*|\s+\.align\s+\d+|\s+\.(SPACE|SUBSPA)\s+\S+|\s*)\n)';
90     $T_COPY_DIRVS   = '^\s+\.(IMPORT|EXPORT)';
91
92     $T_hsc_cc_PAT   = '\.STRING.*\)(hsc|cc) (.*)\\\\x09(.*)\\\\x00';
93     $T_DOT_WORD     = '\.word';
94     $T_DOT_GLOBAL   = '^\s+\.EXPORT';
95     $T_HDR_literal  = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$LIT\$\n";
96     $T_HDR_misc     = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
97     $T_HDR_data     = "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$DATA\$\n\t\.align 4\n";
98     $T_HDR_consist  = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$LIT\$\n";
99     $T_HDR_closure  = "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$DATA\$\n\t\.align 4\n";
100     $T_HDR_info     = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
101     $T_HDR_entry    = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
102     $T_HDR_fast     = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
103     $T_HDR_vector   = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
104     $T_HDR_direct   = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n";
105
106     #--------------------------------------------------------#
107     } elsif ( $TargetPlatform =~ /^i386-.*-(linuxaout|freebsd|nextstep3|cygwin32)/ ) {
108                                 # NeXT added but not tested. CaS
109
110     $T_STABBY       = 1; # 1 iff .stab things (usually if a.out format)
111     $T_US           = '_'; # _ if symbols have an underscore on the front
112     $T_DO_GC        = '_PerformGC_wrapper';
113     $T_PRE_APP      = '^#'; # regexp that says what comes before APP/NO_APP
114     $T_CONST_LBL    = '^LC(\d+):$';
115     $T_POST_LBL     = ':';
116     $T_X86_PRE_LLBL_PAT = 'L';
117     $T_X86_PRE_LLBL         = 'L';
118     $T_X86_BADJMP   = '^\tjmp [^L\*]';
119
120     $T_MOVE_DIRVS   = '^(\s*(\.align\s+\d+(,0x90)?|\.globl\s+\S+|\.text|\.data|\.stab[^n].*|\.type\s+.*|\.size\s+.*)\n)';
121     $T_COPY_DIRVS   = '\.(globl|stab)';
122     $T_hsc_cc_PAT   = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"';
123     $T_DOT_WORD     = '\.long';
124     $T_DOT_GLOBAL   = '\.globl';
125     $T_HDR_literal  = "\.text\n\t\.align 2\n";
126     $T_HDR_misc     = "\.text\n\t\.align 2,0x90\n";
127     $T_HDR_data     = "\.data\n\t\.align 2\n";
128     $T_HDR_consist  = "\.text\n";
129     $T_HDR_closure  = "\.data\n\t\.align 2\n";
130     $T_HDR_info     = "\.text\n\t\.align 2\n"; # NB: requires padding
131     $T_HDR_entry    = "\.text\n"; # no .align so we're right next to _info (arguably wrong...?)
132     $T_HDR_fast     = "\.text\n\t\.align 2,0x90\n";
133     $T_HDR_vector   = "\.text\n\t\.align 2\n"; # NB: requires padding
134     $T_HDR_direct   = "\.text\n\t\.align 2,0x90\n";
135
136     #--------------------------------------------------------#
137     } elsif ( $TargetPlatform =~ /^i386-.*-(solaris2|linux)$/ ) {
138
139     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
140     $T_US           = ''; # _ if symbols have an underscore on the front
141     $T_DO_GC        = 'PerformGC_wrapper';
142     $T_PRE_APP      = # regexp that says what comes before APP/NO_APP
143                       ($TargetPlatform =~ /-linux$/) ? '#' : '/' ;
144     $T_CONST_LBL    = '^\.LC(\d+):$'; # regexp for what such a lbl looks like
145     $T_POST_LBL     = ':';
146     $T_X86_PRE_LLBL_PAT = '\.L';
147     $T_X86_PRE_LLBL         = '.L';
148     $T_X86_BADJMP   = '^\tjmp [^\.\*]';
149
150     $T_MOVE_DIRVS   = '^(\s*(\.align\s+\d+(,0x90)?|\.globl\s+\S+|\.text|\.data|\.section\s+.*|\.type\s+.*|\.Lfe.*\n\t\.size\s+.*|\.size\s+.*|\.ident.*)\n)';
151     $T_COPY_DIRVS   = '\.(globl)';
152
153     $T_hsc_cc_PAT   = '\.string.*\)(hsc|cc) (.*)\\\\t(.*)"';
154     $T_DOT_WORD     = '\.long';
155     $T_DOT_GLOBAL   = '\.globl';
156     $T_HDR_literal  = "\.section\t\.rodata\n"; # or just use .text??? (WDP 95/11)
157     $T_HDR_misc     = "\.text\n\t\.align 16\n";
158     $T_HDR_data     = "\.data\n\t\.align 4\n"; # ToDo: change align??
159     $T_HDR_consist  = "\.text\n";
160     $T_HDR_closure  = "\.data\n\t\.align 4\n"; # ToDo: change align?
161     $T_HDR_info     = "\.text\n\t\.align 16\n"; # NB: requires padding
162     $T_HDR_entry    = "\.text\n"; # no .align so we're right next to _info (arguably wrong...?)
163     $T_HDR_fast     = "\.text\n\t\.align 16\n";
164     $T_HDR_vector   = "\.text\n\t\.align 16\n"; # NB: requires padding
165     $T_HDR_direct   = "\.text\n\t\.align 16\n";
166
167     #--------------------------------------------------------#
168     } elsif ( $TargetPlatform =~ /^m68k-.*-sunos4/ ) {
169
170     $T_STABBY       = 1; # 1 iff .stab things (usually if a.out format)
171     $T_US           = '_'; # _ if symbols have an underscore on the front
172     $T_DO_GC        = '_PerformGC_wrapper';
173     $T_PRE_APP      = '^# MAY NOT APPLY'; # regexp that says what comes before APP/NO_APP
174     $T_CONST_LBL    = '^LC(\d+):$';
175     $T_POST_LBL     = ':';
176
177     $T_MOVE_DIRVS   = '^(\s*(\.align\s+\d+|\.proc\s+\d+|\.const|\.cstring|\.globl\s+\S+|\.text|\.data|\.even|\.stab[^n].*)\n)';
178     $T_COPY_DIRVS   = '\.(globl|proc|stab)';
179     $T_hsc_cc_PAT   = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"';
180
181     $T_DOT_WORD     = '\.long';
182     $T_DOT_GLOBAL   = '\.globl';
183     $T_HDR_literal  = "\.text\n\t\.even\n";
184     $T_HDR_misc     = "\.text\n\t\.even\n";
185     $T_HDR_data     = "\.data\n\t\.even\n";
186     $T_HDR_consist  = "\.text\n";
187     $T_HDR_closure  = "\.data\n\t\.even\n";
188     $T_HDR_info     = "\.text\n\t\.even\n";
189     $T_HDR_entry    = "\.text\n\t\.even\n";
190     $T_HDR_fast     = "\.text\n\t\.even\n";
191     $T_HDR_vector   = "\.text\n\t\.even\n";
192     $T_HDR_direct   = "\.text\n\t\.even\n";
193
194     #--------------------------------------------------------#
195     } elsif ( $TargetPlatform =~ /^mips-.*/ ) {
196
197     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
198     $T_US           = ''; # _ if symbols have an underscore on the front
199     $T_DO_GC        = 'PerformGC_wrapper';
200     $T_PRE_APP      = '^\s*#'; # regexp that says what comes before APP/NO_APP
201     $T_CONST_LBL    = '^\$LC(\d+):$'; # regexp for what such a lbl looks like
202     $T_POST_LBL     = ':';
203
204     $T_MOVE_DIRVS   = '^(\s*(\.align\s+\d+|\.(globl|ent)\s+\S+|\.text|\.r?data)\n)';
205     $T_COPY_DIRVS   = '\.(globl|ent)';
206
207     $T_hsc_cc_PAT   = 'I WAS TOO LAZY TO DO THIS BIT (WDP 95/05)';
208     $T_DOT_WORD     = '\.word';
209     $T_DOT_GLOBAL   = '^\t\.globl';
210     $T_HDR_literal  = "\t\.rdata\n\t\.align 2\n";
211     $T_HDR_misc     = "\t\.text\n\t\.align 2\n";
212     $T_HDR_data     = "\t\.data\n\t\.align 2\n";
213     $T_HDR_consist  = 'TOO LAZY TO DO THIS TOO';
214     $T_HDR_closure  = "\t\.data\n\t\.align 2\n";
215     $T_HDR_info     = "\t\.text\n\t\.align 2\n";
216     $T_HDR_entry    = "\t\.text\n\t\.align 2\n";
217     $T_HDR_fast     = "\t\.text\n\t\.align 2\n";
218     $T_HDR_vector   = "\t\.text\n\t\.align 2\n";
219     $T_HDR_direct   = "\t\.text\n\t\.align 2\n";
220
221     #--------------------------------------------------------#
222     } elsif ( $TargetPlatform =~ /^powerpc-.*|^rs6000-.*/ ) {
223
224     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
225     $T_US           = ''; # _ if symbols have an underscore on the front
226     $T_DO_GC        = '\.PerformGC_wrapper';
227     $T_PRE_APP      = 'NOT APPLICABLE'; # regexp that says what comes before APP/NO_APP
228     $T_CONST_LBL    = 'NOT APPLICABLE'; # regexp for what such a lbl looks like
229     $T_POST_LBL     = ':';
230
231     $T_MOVE_DIRVS   = '^(\s*(\.toc|\.align \d+|\.csect \S+|\t\.?l?globl \S+)\n)';
232     $T_COPY_DIRVS   = '\.(l?globl)';
233
234     $T_hsc_cc_PAT   = '\.byte.*\)(hsc|cc) (.*)"\n\t\.byte \d+\n\t\.byte "(.*)"\n\t\.byte \d+';
235     $T_DOT_WORD     = '\.long';
236     $T_DOT_GLOBAL   = '\.globl';
237     $T_HDR_toc      = "\.toc\n";
238     $T_HDR_literal  = "\.csect .data[RW]\n\t\.align 2\n";               #not RO!?
239     $T_HDR_misc     = "# misc\n\.csect \.text[PR]\n\t\.align 2\n";
240     $T_HDR_data     = "# data\n\.csect \.data[RW]\n\t\.align 2\n";
241     $T_HDR_consist  = "# consist\n\.csect \.data[RW]\n\t\.align 2\n";
242     $T_HDR_closure  = "# closure\n\.csect \.data[RW]\n\t\.align 2\n";
243     $T_HDR_info     = "# info\n\.csect \.data[RW]\n\t\.align 2\n"; #not RO!?
244     $T_HDR_entry    = "# entry\n\.csect \.text[PR]\n\t\.align 2\n";
245     $T_HDR_fast     = "# fast\n\.csect \.text[PR]\n\t\.align 2\n";
246     $T_HDR_vector   = "# vector\n\.csect \.data[RW]\n\t\.align 2\n"; #not RO!?
247     $T_HDR_direct   = "# direct\n";
248
249     #--------------------------------------------------------#
250     } elsif ( $TargetPlatform =~ /^sparc-.*-solaris2/ ) {
251
252     $T_STABBY       = 0; # 1 iff .stab things (usually if a.out format)
253     $T_US           = ''; # _ if symbols have an underscore on the front
254     $T_DO_GC        = 'PerformGC_wrapper';
255     $T_PRE_APP      = 'DOES NOT SEEM TO APPLY'; # regexp that says what comes before APP/NO_APP
256     $T_CONST_LBL    = '^\.LLC(\d+):$'; # regexp for what such a lbl looks like
257     $T_POST_LBL     = ':';
258
259     $T_MOVE_DIRVS   = '^((\s+\.align\s+\d+|\s+\.proc\s+\d+|\s+\.global\s+\S+|\.text|\.data|\.stab.*|\.section.*|\s+\.type.*|\s+\.size.*)\n)';
260     $T_COPY_DIRVS   = '\.(global|proc|stab)';
261
262     $T_hsc_cc_PAT   = '\.asciz.*\)(hsc|cc) (.*)\\\\t(.*)"';
263     $T_DOT_WORD     = '\.word';
264     $T_DOT_GLOBAL   = '^\t\.global';
265     $T_HDR_literal  = "\.text\n\t\.align 8\n";
266     $T_HDR_misc     = "\.text\n\t\.align 4\n";
267     $T_HDR_data     = "\.data\n\t\.align 8\n";
268     $T_HDR_consist  = "\.text\n";
269     $T_HDR_closure  = "\.data\n\t\.align 4\n";
270     $T_HDR_info     = "\.text\n\t\.align 4\n";
271     $T_HDR_entry    = "\.text\n\t\.align 4\n";
272     $T_HDR_fast     = "\.text\n\t\.align 4\n";
273     $T_HDR_vector   = "\.text\n\t\.align 4\n";
274     $T_HDR_direct   = "\.text\n\t\.align 4\n";
275
276     #--------------------------------------------------------#
277     } elsif ( $TargetPlatform =~ /^sparc-.*-sunos4/ ) {
278
279     $T_STABBY       = 1; # 1 iff .stab things (usually if a.out format)
280     $T_US           = '_'; # _ if symbols have an underscore on the front
281     $T_DO_GC        = '_PerformGC_wrapper';
282     $T_PRE_APP      = '^# DOES NOT SEEM TO APPLY'; # regexp that says what comes before APP/NO_APP
283     $T_CONST_LBL    = '^LC(\d+):$';
284     $T_POST_LBL     = ':';
285
286     $T_MOVE_DIRVS   = '^((\s+\.align\s+\d+|\s+\.proc\s+\d+|\s+\.global\s+\S+|\.text|\.data|\.stab.*)\n)';
287     $T_COPY_DIRVS   = '\.(global|proc|stab)';
288     $T_hsc_cc_PAT   = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"';
289
290     $T_DOT_WORD     = '\.word';
291     $T_DOT_GLOBAL   = '^\t\.global';
292     $T_HDR_literal  = "\.text\n\t\.align 8\n";
293     $T_HDR_misc     = "\.text\n\t\.align 4\n";
294     $T_HDR_data     = "\.data\n\t\.align 8\n";
295     $T_HDR_consist  = "\.text\n";
296     $T_HDR_closure  = "\.data\n\t\.align 4\n";
297     $T_HDR_info     = "\.text\n\t\.align 4\n";
298     $T_HDR_entry    = "\.text\n\t\.align 4\n";
299     $T_HDR_fast     = "\.text\n\t\.align 4\n";
300     $T_HDR_vector   = "\.text\n\t\.align 4\n";
301     $T_HDR_direct   = "\.text\n\t\.align 4\n";
302
303     #--------------------------------------------------------#
304     } else {
305         print STDERR "$Pgm: don't know how to mangle assembly language for: $TargetPlatform\n";
306         exit 1;
307     }
308
309 if ( 0 ) {
310 print STDERR "T_STABBY: $T_STABBY\n";
311 print STDERR "T_US: $T_US\n";
312 print STDERR "T_DO_GC: $T_DO_GC\n";
313 print STDERR "T_PRE_APP: $T_PRE_APP\n";
314 print STDERR "T_CONST_LBL: $T_CONST_LBL\n";
315 print STDERR "T_POST_LBL: $T_POST_LBL\n";
316 if ( $TargetPlatform =~ /^i386-/ ) {
317     print STDERR "T_X86_PRE_LLBL_PAT: $T_X86_PRE_LLBL_PAT\n";
318     print STDERR "T_X86_PRE_LLBL: $T_X86_PRE_LLBL\n";
319     print STDERR "T_X86_BADJMP: $T_X86_BADJMP\n";
320 }
321 print STDERR "T_MOVE_DIRVS: $T_MOVE_DIRVS\n";
322 print STDERR "T_COPY_DIRVS: $T_COPY_DIRVS\n";
323 print STDERR "T_hsc_cc_PAT: $T_hsc_cc_PAT\n";
324 print STDERR "T_DOT_WORD: $T_DOT_WORD\n";
325 print STDERR "T_HDR_literal: $T_HDR_literal\n";
326 print STDERR "T_HDR_misc: $T_HDR_misc\n";
327 print STDERR "T_HDR_data: $T_HDR_data\n";
328 print STDERR "T_HDR_consist: $T_HDR_consist\n";
329 print STDERR "T_HDR_closure: $T_HDR_closure\n";
330 print STDERR "T_HDR_info: $T_HDR_info\n";
331 print STDERR "T_HDR_entry: $T_HDR_entry\n";
332 print STDERR "T_HDR_fast: $T_HDR_fast\n";
333 print STDERR "T_HDR_vector: $T_HDR_vector\n";
334 print STDERR "T_HDR_direct: $T_HDR_direct\n";
335 }
336
337 }
338 \end{code}
339
340 %************************************************************************
341 %*                                                                      *
342 \subsection{Mangle away}
343 %*                                                                      *
344 %************************************************************************
345
346 \begin{code}
347 sub mangle_asm {
348     local($in_asmf, $out_asmf) = @_;
349
350     # multi-line regexp matching:
351     local($*) = 1;
352     local($i, $c);
353
354
355     &init_TARGET_STUFF();
356     &init_FUNNY_THINGS();
357
358     # perl4 on alphas SEGVs when give ${foo} substitutions in patterns.
359     # To avoid them we declare some locals that allows to avoid using curlies.
360     local($TUS)      = ${T_US};
361     local($TPOSTLBL) = ${T_POST_LBL};
362     local($TMOVEDIRVS) = ${T_MOVE_DIRVS};
363     local($TPREAPP)    = ${T_PRE_APP};
364     local($TCOPYDIRVS) = ${T_COPY_DIRVS};
365     local($TDOTWORD)   = ${T_DOT_WORD};
366
367     open(INASM, "< $in_asmf")
368         || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n");
369     open(OUTASM,"> $out_asmf")
370         || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n");
371
372     # read whole file, divide into "chunks":
373     #   record some info about what we've found...
374
375     @chk = ();          # contents of the chunk
376     $numchks = 0;       # number of them
377     @chkcat = ();       # what category of thing in each chunk
378     @chksymb = ();      # what symbol(base) is defined in this chunk
379     %slowchk = ();      # ditto, its regular "slow" entry code
380     %fastchk = ();      # ditto, fast entry code
381     %closurechk = ();   # ditto, the (static) closure
382     %infochk = ();      # given a symbol base, say what chunk its info tbl is in
383     %vectorchk = ();    # ditto, return vector table
384     %directchk = ();    # ditto, direct return code
385     $EXTERN_DECLS = ''; # .globl <foo> .text (MIPS only)
386
387     $i = 0; $chkcat[0] = 'misc'; $chk[0] = '';
388
389     while (<INASM>) {
390         next if $T_STABBY && /^\.stab.*$TUS[@]?__stg_split_marker/o;
391         next if $T_STABBY && /^\.stab.*ghc.*c_ID/;
392         next if /$TPREAPP(NO_)?APP/o; 
393         next if /^;/ && $TargetPlatform =~ /^hppa/;
394
395         next if /(^$|^\t\.file\t|^ # )/ && $TargetPlatform =~ /^(mips|powerpc|rs6000)-/;
396
397         last if /^_section_\.text:$/ && $TargetPlatform =~ /^powerpc-|^rs6000-/;
398
399         if ( $TargetPlatform =~ /^mips-/ 
400           && /^\t\.(globl \S+ \.text|comm\t)/ ) {
401             $EXTERN_DECLS .= $_ unless /(__DISCARD__|\b(PK_|ASSIGN_)(FLT|DBL)\b)/;
402   
403         } elsif ( /^\s+/ ) { # most common case first -- a simple line!
404             # duplicated from the bottom
405
406             $chk[$i] .= $_;
407
408         } elsif ( /\.\.ng:$/ && $TargetPlatform =~ /^alpha-/ ) {
409             # Alphas: Local labels not to be confused with new chunks
410             $chk[$i] .= $_;
411   
412         # NB: all the rest start with a non-space
413
414         } elsif ( $TargetPlatform =~ /^mips-/
415                && /^\d+:/ ) { # a funny-looking very-local label
416             $chk[$i] .= $_;
417
418         } elsif ( /$T_CONST_LBL/o ) {
419             $chk[++$i]   = $_;
420             $chkcat[$i]  = 'literal';
421             $chksymb[$i] = $1;
422
423         } elsif ( /^$TUS[@]?__stg_split_marker(\d+)$TPOSTLBL[@]?$/o ) {
424             $chk[++$i]   = $_;
425             $chkcat[$i]  = 'splitmarker';
426             $chksymb[$i] = $1;
427
428         } elsif ( /^$TUS[@]?([A-Za-z0-9_]+)_info$TPOSTLBL[@]?$/o ) {
429             $symb = $1;
430             $chk[++$i]   = $_;
431             $chkcat[$i]  = 'infotbl';
432             $chksymb[$i] = $symb;
433
434             die "Info table already? $symb; $i\n" if defined($infochk{$symb});
435
436             $infochk{$symb} = $i;
437
438         } elsif ( /^$TUS[@]?([A-Za-z0-9_]+)_entry$TPOSTLBL[@]?$/o ) {
439             $chk[++$i]   = $_;
440             $chkcat[$i]  = 'slow';
441             $chksymb[$i] = $1;
442
443             $slowchk{$1} = $i;
444
445         } elsif ( /^$TUS[@]?([A-Za-z0-9_]+)_fast\d+$TPOSTLBL[@]?$/o ) {
446             $chk[++$i]   = $_;
447             $chkcat[$i]  = 'fast';
448             $chksymb[$i] = $1;
449
450             $fastchk{$1} = $i;
451
452         } elsif ( /^$TUS[@]?([A-Za-z0-9_]+)_closure$TPOSTLBL[@]?$/o ) {
453             $chk[++$i]   = $_;
454             $chkcat[$i]  = 'closure';
455             $chksymb[$i] = $1;
456
457             $closurechk{$1} = $i;
458
459         } elsif ( /^$TUS[@]?ghc.*c_ID$TPOSTLBL/o ) {
460             $chk[++$i]  = $_;
461             $chkcat[$i] = 'consist';
462
463         } elsif ( /^($TUS[@]?__gnu_compiled_c|gcc2_compiled\.)$TPOSTLBL/o ) {
464             ; # toss it
465
466         } elsif ( /^$TUS[@]?ErrorIO_call_count$TPOSTLBL[@]?$/o  # HACK!!!!
467                || /^$TUS[A-Za-z0-9_]+\.\d+$TPOSTLBL[@]?$/o
468                || /^$TUS[@]?.*_CAT$TPOSTLBL[@]?$/o              # PROF: _entryname_CAT
469                || /^$TUS[@]?CC_.*_struct$TPOSTLBL[@]?$/o        # PROF: _CC_ccident_struct
470                || /^$TUS[@]?.*_done$TPOSTLBL[@]?$/o             # PROF: _module_done
471                || /^$TUS[@]?_module_registered$TPOSTLBL[@]?$/o  # PROF: _module_registered
472                ) {
473             $chk[++$i]   = $_;
474             $chkcat[$i]  = 'data';
475             $chksymb[$i] = '';
476
477         } elsif ( /^([A-Za-z0-9_]+)\s+\.comm/ && $TargetPlatform =~ /^hppa/ ) {
478             $chk[++$i]   = $_;
479             $chkcat[$i]  = 'bss';
480             $chksymb[$i] = '';
481
482         } elsif ( $TargetPlatform =~ /^powerpc-|^rs6000-/ && /^LC\.\.([0-9]+)/ ) {
483             $chk[++$i]   = $_;
484             $chkcat[$i]  = 'toc';
485             $chksymb[$i] = $1;
486  
487         } elsif ( /^($TUS[@]?(ret_|djn_)[A-Za-z0-9_]+)/o ) {
488             $chk[++$i]   = $_;
489             $chkcat[$i]  = 'misc';
490             $chksymb[$i] = '';
491             $symbtmp = $1;
492             $chksymb[$i] = $symbtmp if ($TargetPlatform =~ /^powerpc-|^rs6000-/) ; #rm andre
493
494         } elsif ( /^$TUS[@]?vtbl_([A-Za-z0-9_]+)$TPOSTLBL[@]?$/o ) {
495             $chk[++$i]   = $_;
496             $chkcat[$i]  = 'vector';
497             $chksymb[$i] = $1;
498
499             $vectorchk{$1} = $i;
500
501         } elsif ( /^$TUS[@]?([A-Za-z0-9_]+)DirectReturn$TPOSTLBL[@]?$/o ) {
502             $chk[++$i]   = $_;
503             $chkcat[$i]  = 'direct';
504             $chksymb[$i] = $1;
505
506             $directchk{$1} = $i;
507
508         } elsif ( /^$TUS[@]?([A-Za-z0-9_]+)_upd$TPOSTLBL[@]?$/o ) {
509             $chk[++$i]   = $_;
510             $chkcat[$i]  = 'misc';
511             print STDERR "_upd!!!!! I guess this code is dead!!!!\n";
512             # I guess this is never entered, since all _upds are 
513             # either vtbl_'s or ret_'s, caught above. - andre
514             $chksymb[$i] = ''; 
515
516         } elsif ( $TargetPlatform =~ /^i386-.*-solaris2/
517              &&   /^(_uname|uname|stat|fstat):/ ) {
518             # for some utterly bizarre reason, this platform
519             # likes to drop little local C routines with these names
520             # into each and every .o file that #includes the
521             # relevant system .h file.  Yuck.  We just don't
522             # tolerate them in .hc files (which we are processing
523             # here).  If you need to call one of these things from
524             # Haskell, make a call to your own C wrapper, then
525             # put that C wrapper (which calls one of these) in a
526             # plain .c file.  WDP 95/12
527             $chk[++$i]   = $_;
528             $chkcat[$i]  = 'toss';
529             $chksymb[$i] = $1;
530
531         } elsif ( /^$TUS[@]?[A-Za-z0-9_]/o
532                 && ( $TargetPlatform !~ /^hppa/ # need to avoid local labels in this case
533                    || ! /^L\$\d+$/ )
534                 && ( $TargetPlatform !~ /^powerpc|^rs6000/ # ditto
535                    || ! /^(L\.\.\d+|LT\.\..*):$/ ) ) {
536             local($thing);
537             chop($thing = $_);
538             print STDERR "Funny global thing?: $_"
539                 unless $KNOWN_FUNNY_THING{$thing}
540                     || /^$TUS[@]?_(PRIn|PRStart).*$TPOSTLBL[@]?$/o # pointer reversal GC routines
541                     || /^$TUS[@]?CC_.*$TPOSTLBL$/o              # PROF: _CC_ccident  ([@]? is a silly hack (see above))
542                     || /^$TUS[@]?_reg.*$TPOSTLBL$/o;            # PROF: __reg<module>
543             $chk[++$i]   = $_;
544             $chkcat[$i]  = 'misc';
545             if ($TargetPlatform =~ /^powerpc-|^rs6000-/) 
546                { $chksymb[$i] = $thing; }
547             else { $chksymb[$i] = ''; };
548
549         } else { # simple line (duplicated at the top)
550
551             $chk[$i] .= $_;
552         }
553     }
554     $numchks = $#chk + 1;
555
556     # the division into chunks is imperfect;
557     # we throw some things over the fence into the next
558     # chunk.
559     #
560     # also, there are things we would like to know
561     # about the whole module before we start spitting
562     # output.
563
564     local($FIRST_MANGLABLE) = ($TargetPlatform =~ /^(alpha-|hppa|mips-)/) ? 1 : 0;
565
566 #   print STDERR "first chunk to mangle: $FIRST_MANGLABLE\n";
567
568     # Alphas: NB: we start meddling at chunk 1, not chunk 0
569     # The first ".rdata" is quite magical; as of GCC 2.7.x, it
570     # spits a ".quad 0" in after the v first ".rdata"; we
571     # detect this special case (tossing the ".quad 0")!
572     local($magic_rdata_seen) = 0;
573   
574     # HPPAs, MIPSen: also start medding at chunk 1
575
576     if ($TargetPlatform =~ /^powerpc|^rs6000/) {
577        print OUTASM $T_HDR_toc; # yes, we have to put a .toc 
578                                 # in the beginning of every file!
579     %tocequiv = ();          # maps toc symbol number to toc symbol
580     %revtocequiv = ();       # maps toc symbol to toc symbol number
581     for ($i = 1; $i < $numchks; $i++) {
582         $chk[$i] =~ s/\[RW\]//g;
583         $chk[$i] =~ s/\[DS\]//g;
584         $chk[$i] =~ s/^\.csect .*\[DS\]$//g;
585
586         if ( $chkcat[$i] eq 'toc' && $chk[$i] !~ /\.byte/ )
587            { $chk[$i] =~ s/$T_MOVE_DIRVS//g;
588              $chk[$i] =~ s/\t\.tc (\S+)\[TC\],(\S+_fast\d+)/\t\.tc \1\[TC\],\.\2/; 
589              $chk[$i] =~ s/\t\.tc (\S+)\[TC\],(\S+_entry)\n/\t\.tc \1\[TC\],\.\2\n/;
590              $chk[$i] =~ s/\t\.tc (\S+)\[TC\],(ret_\S+)/\t\.tc \1\[TC\],\.\2/;
591              $chk[$i] =~ s/\t\.tc (\S+)\[TC\],(djn_\S+)/\t\.tc \1\[TC\],\.\2/;
592              $chk[$i] =~ s/\t\.tc (\S+)\[TC\],(vtbl_\S+)/\t\.tc \1\[TC\],\.\2/;
593              $chk[$i] =~ s/\t\.tc (\S+)\[TC\],ErrorIO_innards/\t\.tc \1\[TC\],\.ErrorIO_innards/;
594              $chk[$i] =~ s/\t\.tc (\S+)\[TC\],startStgWorld/\t\.tc \1\[TC\],\.startStgWorld/;
595              $chk[$i] =~ s/\.tc UpdatePAP\[TC\],UpdatePAP/\.tc UpdatePAP\[TC\],\.UpdatePAP/;
596              $chk[$i] =~ s/\.tc IndUpdRetDir\[TC\],IndUpdRetDir/\.tc IndUpdRetDir\[TC\],\.IndUpdRetDir/;
597              $chk[$i] =~ s/\t\.tc (_PRStart_\S+)\[TC\],_PRStart_\S+/\t\.tc \1\[TC\],\.\1/;
598
599              $tocnumber = $chksymb[$i];
600              $tocsymb = $chk[$i];
601              $tocsymb =~ s/^LC\.\.\d+:\n//;
602              $tocsymb =~ s/^\t\.tc \S+,(\S+)\n/\1/;
603              $tocequiv{$tocnumber} = $tocsymb;
604
605            } elsif ( $chkcat[$i] eq 'toc' && $chk[$i] =~ /\.byte/ ) {
606              $chkcat[$i] = 'literal';
607            }
608     }
609     };
610
611     for ($i = $FIRST_MANGLABLE; $i < $numchks; $i++) {
612         $c = $chk[$i]; # convenience copy
613
614 #       print STDERR "\nCHK $i (BEFORE) (",$chkcat[$i],"):\n", $c;
615
616         # toss all prologue stuff; HPPA is pretty weird
617         # (see elsewhere)
618         $c = &mash_hppa_prologue($c) if $TargetPlatform =~ /^hppa/;
619
620         # be slightly paranoid to make sure there's
621         # nothing surprising in there
622         if ( $c =~ /--- BEGIN ---/ ) {
623             if (($p, $r) = split(/--- BEGIN ---/, $c)) {
624
625                 if ($TargetPlatform =~ /^i386-/) {
626                     $p =~ s/^\tpushl \%edi\n//;
627                     $p =~ s/^\tpushl \%esi\n//;
628                     $p =~ s/^\tsubl \$\d+,\%esp\n//;
629                     $p =~ s/^\tmovl \$\d+,\%eax\n\tcall __alloca\n// if ($TargetPlatform =~ /^.*-cygwin32/);
630                 } elsif ($TargetPlatform =~ /^m68k-/) {
631                     $p =~ s/^\tlink a6,#-?\d.*\n//;
632                     $p =~ s/^\tpea a6@\n\tmovel sp,a6\n//;    
633                                 # The above showed up in the asm code,
634                                 # so I added it here.
635                                 # I hope it's correct.
636                                 # CaS
637                     $p =~ s/^\tmovel d2,sp\@-\n//;
638                     $p =~ s/^\tmovel d5,sp\@-\n//; # SMmark.* only?
639                     $p =~ s/^\tmoveml \#0x[0-9a-f]+,sp\@-\n//; # SMmark.* only?
640                 } elsif ($TargetPlatform =~ /^mips-/) {
641                     # the .frame/.mask/.fmask that we use is the same
642                     # as that produced by GCC for miniInterpret; this
643                     # gives GDB some chance of figuring out what happened
644                     $FRAME = "\t.frame\t\$sp,2168,\$31\n\t.mask\t0x90000000,-4\n\t.fmask\t0x00000000,0\n";
645                     $p =~ s/^\t\.(frame).*\n/__FRAME__/g;
646                     $p =~ s/^\t\.(mask|fmask).*\n//g;
647                     $p =~ s/^\t\.cprestore.*\n/\t\.cprestore 416\n/; # 16 + 100 4-byte args
648                     $p =~ s/^\tsubu\t\$sp,\$sp,\d+\n//;
649                     $p =~ s/^\tsw\t\$31,\d+\(\$sp\)\n//;
650                     $p =~ s/^\tsw\t\$fp,\d+\(\$sp\)\n//;
651                     $p =~ s/^\tsw\t\$28,\d+\(\$sp\)\n//;
652                     $p =~ s/__FRAME__/$FRAME/;
653                 } elsif ($TargetPlatform =~ /^powerpc-|^rs6000/) {
654                     $p =~ s/^\tmflr 0\n//;
655                     $p =~ s/^\tstm \d+,-\d+\(1\)\n//;
656                     $p =~ s/^\tstw? 0,\d+\(1\)\n//;
657                     $p =~ s/^\tstw?u 1,-\d+\(1\)\n//; 
658                     $p =~ s/^\tstw? \d+,-\d+\(1\)\n//g; 
659                     $p =~ s/^\tstfd \d+,-\d+\(1\)\n//g; 
660                 } else {
661                     print STDERR "$Pgm: unknown prologue mangling? $TargetPlatform\n";
662                 }
663
664                 die "Prologue junk?: $p\n" if $p =~ /^\t[^\.]/
665                     && $TargetPlatform !~ /^powerpc-/; #ToDo: remove test
666
667                 # glue together what's left
668                 $c = $p . $r;
669                 $c =~ s/\n\t\n/\n/; # junk blank line
670             }
671         }
672
673         if ( $TargetPlatform =~ /^mips-/ ) {
674             # MIPS: first, this basic sequence may occur "--- END ---" or not
675             $c =~ s/^\tlw\t\$31,\d+\(\$sp\)\n\taddu\t\$sp,\$sp,\d+\n\tj\t\$31\n\t\.end/\t\.end/;
676         }
677
678         # toss all epilogue stuff; again, paranoidly
679         if ( $c =~ /--- END ---/ ) {
680             if (($r, $e) = split(/--- END ---/, $c)) {
681                 if ($TargetPlatform =~ /^i386-/) {
682                     $e =~ s/^\tret\n//;
683                     $e =~ s/^\tpopl \%edi\n//;
684                     $e =~ s/^\tpopl \%esi\n//;
685                     $e =~ s/^\taddl \$\d+,\%esp\n//;
686                 } elsif ($TargetPlatform =~ /^m68k-/) {
687                     $e =~ s/^\tunlk a6\n//;
688                     $e =~ s/^\trts\n//;
689                 } elsif ($TargetPlatform =~ /^mips-/) {
690                     $e =~ s/^\tlw\t\$31,\d+\(\$sp\)\n//;
691                     $e =~ s/^\tlw\t\$fp,\d+\(\$sp\)\n//;
692                     $e =~ s/^\taddu\t\$sp,\$sp,\d+\n//;
693                     $e =~ s/^\tj\t\$31\n//;
694                 } elsif ($TargetPlatform =~ /^powerpc-|^rs6000-/) {
695                     $e =~ s/^\taddi 1,1,\d+\n//;
696                     $e =~ s/^\tcal 1,\d+\(1\)\n//;
697                     $e =~ s/^\tlw?z? \d+,\d+\(1\)\n//; 
698                     $e =~ s/^\tmtlr 0\n//;
699                     $e =~ s/^\tbl?r\n//;
700                 } else {
701                     print STDERR "$Pgm: unknown epilogue mangling? $TargetPlatform\n";
702                 }
703                 die "Epilogue junk?: $e\n" if $e =~ /^\t[^\.]/
704                     && $TargetPlatform !~ /^powerpc-/; #ToDo: remove test
705
706                 # glue together what's left
707                 $c = $r . $e;
708                 $c =~ s/\n\t\n/\n/; # junk blank line
709             }
710         }
711
712         # On SPARCs, we don't do --- BEGIN/END ---, we just
713         # toss the register-windowing save/restore/ret* instructions
714         # directly:
715         if ( $TargetPlatform =~ /^sparc-/ ) {
716             $c =~ s/^\t(save .*|restore|ret|retl)\n//g;
717             # throw away PROLOGUE comments
718             $c =~ s/^\t!#PROLOGUE# 0\n\t!#PROLOGUE# 1\n//;
719         }
720
721         # On Alphas, the prologue mangling is done a little later (below)
722
723         # toss all calls to __DISCARD__
724         $c =~ s/^\t(call|jbsr|jal)\s+$TUS[@]?__DISCARD__\n//go;
725
726         # MIPS: that may leave some gratuitous asm macros around
727         # (no harm done; but we get rid of them to be tidier)
728         $c =~ s/^\t\.set\tnoreorder\n\t\.set\tnomacro\n\taddu\t(\S+)\n\t\.set\tmacro\n\t\.set\treorder\n/\taddu\t$1\n/
729             if $TargetPlatform =~ /^mips-/;
730
731         # toss stack adjustment after DoSparks
732         $c =~ s/^(\tjbsr _DoSparks\n)\taddqw #8,sp/$1/g
733                 if $TargetPlatform =~ /^m68k-/; # this looks old...
734
735         if ( $TargetPlatform =~ /^alpha-/ &&
736            ! $magic_rdata_seen &&
737            $c =~ /^\s*\.rdata\n\t\.quad 0\n\t\.align \d\n/ ) {
738             $c =~ s/^\s*\.rdata\n\t\.quad 0\n\t\.align (\d)\n/\.rdata\n\t\.align $1\n/;
739             $magic_rdata_seen = 1;
740         }
741
742         # pick some end-things and move them to the next chunk
743
744         # pin a funny end-thing on (for easier matching):
745         $c .= 'FUNNY#END#THING';
746
747         while ( $c =~ /$TMOVEDIRVS[@]?FUNNY#END#THING/o ) {  # [@]? is a silly hack to avoid having to use curlies for T_PRE_APP
748                                                            # (this SEGVs perl4 on alphas, you see)
749
750             $to_move = $1;
751             if ( $i < ($numchks - 1)
752               && ( $to_move =~ /$TCOPYDIRVS/
753                 || ($TargetPlatform =~ /^hppa/ && $to_move =~ /align/ && $chkcat[$i+1] eq 'literal') )) {
754                 $chk[$i + 1] = $to_move . $chk[$i + 1];
755                 # otherwise they're tossed
756             }
757
758             $c =~ s/$TMOVEDIRVS[@]?FUNNY#END#THING/FUNNY#END#THING/o; # [@]? is a hack (see above)
759         }
760
761         if ( $TargetPlatform =~ /^alpha-/ && $c =~ /^\t\.ent\s+(\S+)/ ) {
762             $ent = $1;
763             # toss all prologue stuff, except for loading gp, and the ..ng address
764             if (($p, $r) = split(/^\t\.prologue/, $c)) {
765                 if (($keep, $junk) = split(/\.\.ng:/, $p)) {
766                     $c = $keep . "..ng:\n";
767                 } else {
768                     print STDERR "malformed code block ($ent)?\n"
769                 }
770             }
771             $c .= "\t.frame \$30,0,\$26,0\n\t.prologue" . $r;
772         }
773   
774         $c =~ s/FUNNY#END#THING//;
775
776 #       print STDERR "\nCHK $i (AFTER) (",$chkcat[$i],"):\n", $c;
777
778         $chk[$i] = $c; # update w/ convenience copy
779     }
780
781     if ( $TargetPlatform =~ /^alpha-/ ) {
782         # print out the header stuff first
783         $chk[0] =~ s/^(\t\.file.*)"(ghc\d+\.c)"/$1"$ifile_root.hc"/;
784         print OUTASM $chk[0];
785
786     } elsif ( $TargetPlatform =~ /^hppa/ ) {
787         print OUTASM $chk[0];
788
789     } elsif ( $TargetPlatform =~ /^mips-/ ) {
790         $chk[0] = "\t\.file\t1 \"$ifile_root.hc\"\n" . $chk[0];
791
792         # get rid of horrible "<dollar>Revision: .*$" strings
793         local(@lines0) = split(/\n/, $chk[0]);
794         local($z) = 0;
795         while ( $z <= $#lines0 ) {
796             if ( $lines0[$z] =~ /^\t\.byte\t0x24,0x52,0x65,0x76,0x69,0x73,0x69,0x6f$/ ) {
797                 undef($lines0[$z]);
798                 $z++;
799                 while ( $z <= $#lines0 ) {
800                     undef($lines0[$z]);
801                     last if $lines0[$z] =~ /[,\t]0x0$/;
802                     $z++;
803                 }
804             }
805             $z++;
806         }
807         $chk[0] = join("\n", @lines0);
808         $chk[0] =~ s/\n\n+/\n/;
809         print OUTASM $chk[0];
810     }
811
812     # print out all the literal strings next
813     for ($i = 0; $i < $numchks; $i++) {
814         if ( $chkcat[$i] eq 'literal' ) {
815             print OUTASM $T_HDR_literal, $chk[$i];
816             print OUTASM "; end literal\n" if $TargetPlatform =~ /^hppa/; # for the splitter
817
818             $chkcat[$i] = 'DONE ALREADY';
819         }
820     }
821
822     # on the HPPA, print out all the bss next
823     if ( $TargetPlatform =~ /^hppa/ ) {
824         for ($i = 1; $i < $numchks; $i++) {
825             if ( $chkcat[$i] eq 'bss' ) {
826                 print OUTASM "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$BSS\$\n\t.align 4\n";
827                 print OUTASM $chk[$i];
828
829                 $chkcat[$i] = 'DONE ALREADY';
830             }
831         }
832     }
833
834     for ($i = $FIRST_MANGLABLE; $i < $numchks; $i++) {
835 #       print STDERR "$i: cat $chkcat[$i], symb $chksymb[$i]\n";
836
837         next if $chkcat[$i] eq 'DONE ALREADY';
838
839         if ( $chkcat[$i] eq 'misc' ) {
840             if ($chk[$i] ne '') {
841                 print OUTASM $T_HDR_misc;
842                 if ($TargetPlatform =~ /^powerpc-|^rs6000/) { 
843                    $chksymb[$i] =~ s/://;
844 #new                   if ($chksymb[$i] =~ /ret.*upd/ || $KNOWN_FUNNY_THING{$chksymb[$i]}
845 #new                    || $chksymb[$i] =~ /^$.{T_US}_(PRIn|PRStart).*${T_POST_LBL}$/o )
846 #new                      { print OUTASM "\t\.globl $chksymb[$i]\n"; }
847                    if ($chksymb[$i] ne '') 
848                        { print OUTASM "\t\.globl \.$chksymb[$i]\n"; };
849                    if ($chk[$i] =~ /TOC\[tc0\], 0\n/)
850                      { ($p, $r) = split(/TOC\[tc0\], 0\n/, $chk[$i]); $printDS = 1;}
851                    else { $r = $chk[$i]; $printDS = 0; };
852                    $chk[$i] = &mangle_powerpc_tailjump($r);
853                 };
854                 &print_doctored($chk[$i], 0);
855                 if ($TargetPlatform =~ /^powerpc-|^rs6000-/ && $printDS) { 
856                    print OUTASM "\.csect ${chksymb[$i]}[DS]\n";         
857                    print OUTASM "${p}TOC[tc0], 0\n";
858                 }
859             }
860
861         } elsif ( $chkcat[$i] eq 'toss' ) {
862             print STDERR "*** NB: TOSSING code for $chksymb[$i] !!! ***\n";
863
864         } elsif ( $chkcat[$i] eq 'data' ) {
865             if ($chk[$i] ne '') {
866                 print OUTASM $T_HDR_data;
867                 print OUTASM $chk[$i];
868             }
869
870         } elsif ( $chkcat[$i] eq 'consist' ) {
871             if ( $chk[$i] =~ /$T_hsc_cc_PAT/o ) {
872                 local($consist) = "$1.$2.$3";
873                 $consist =~ s/,/./g;
874                 $consist =~ s/\//./g;
875                 $consist =~ s/-/_/g;
876                 $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly?
877                 print OUTASM $T_HDR_consist, "${consist}${T_POST_LBL}\n";
878
879             } elsif ( $TargetPlatform !~ /^(mips)-/ ) { # we just don't try in those case (ToDo)
880                 # on mips: consistency string is just a v
881                 # horrible bunch of .bytes,
882                 # which I am too lazy to sort out (WDP 95/05)
883
884                 print STDERR "Couldn't grok consistency: ", $chk[$i];
885             }
886
887         } elsif ( $chkcat[$i] eq 'splitmarker' ) {
888             # we can just re-constitute this one...
889             # NB: we emit _three_ underscores no matter what,
890             # so ghc-split doesn't have to care.
891             print OUTASM "___stg_split_marker",$chksymb[$i],"${T_POST_LBL}\n";
892
893         } elsif ( $chkcat[$i] eq 'closure'
894                || $chkcat[$i] eq 'infotbl'
895                || $chkcat[$i] eq 'slow'
896                || $chkcat[$i] eq 'fast' ) { # do them in that order
897             $symb = $chksymb[$i];
898
899             # CLOSURE
900             if ( defined($closurechk{$symb}) ) {
901                 print OUTASM $T_HDR_closure;
902                 print OUTASM $chk[$closurechk{$symb}];
903                 $chkcat[$closurechk{$symb}] = 'DONE ALREADY';
904             }
905
906             # INFO TABLE
907             if ( defined($infochk{$symb}) ) {
908
909                 print OUTASM $T_HDR_info;
910                 if ($TargetPlatform =~ /^powerpc-|^rs6000-/) {
911                   $chk[$infochk{$symb}] =~ s/\.long ([_A-Za-z]\S+_entry)/\.long \.\1/;
912                   $chk[$infochk{$symb}] =~ s/\.long ([A-Za-z]\S+_upd)/\.long \.\1/;
913                   $chk[$infochk{$symb}] =~ s/\.long (IndUpdRet\S+)/\.long \.\1/;
914                   $chk[$infochk{$symb}] =~ s/\.long StdErrorCode/\.long \.StdErrorCode/;
915                   $chk[$infochk{$symb}] =~ s/\.long UpdErr/\.long \.UpdErr/;
916                   print OUTASM $chk[$infochk{$symb}];
917                 } else {
918                 print OUTASM &rev_tbl($symb, $chk[$infochk{$symb}], 1);
919                 }
920                 # entry code will be put here!
921
922                 # paranoia
923                 if ( $chk[$infochk{$symb}] =~ /$TDOTWORD[@]?\s+([A-Za-z0-9_]+_entry)$/o
924                   && $1 ne "${T_US}${symb}_entry" ) {
925                     print STDERR "!!! entry point???\n",$chk[$infochk{$symb}];
926                 }
927
928                 $chkcat[$infochk{$symb}] = 'DONE ALREADY';
929             }
930
931             # STD ENTRY POINT
932             if ( defined($slowchk{$symb}) ) {
933
934                 # teach it to drop through to the fast entry point:
935                 $c = $chk[$slowchk{$symb}];
936
937                 if ($TargetPlatform =~ /^powerpc-|^rs6000-/) { 
938                 ($p, $r) = split(/TOC\[tc0\], 0\n/, $c); 
939                 if ($symb =~ /^[_A-Z]/)
940                 { 
941                   print OUTASM "\t\.globl \.${chksymb[$i]}_entry\n"; 
942                   print OUTASM "\.csect ${symb}_entry[DS]\n";   
943                   print OUTASM "${p}TOC[tc0], 0\n";
944                   }; 
945                   $r =~ s/\.csect \.text\[PR\]\n//; # todo: properly - andre
946                   $c = &mangle_powerpc_tailjump($r);
947                 };
948
949                 if ( defined($fastchk{$symb}) ) {
950                     if ( $TargetPlatform =~ /^alpha-/ ) {
951                         $c =~ s/^\tjmp \$31,\(\$27\),0\n\t\.align 4\n\t\.end/\t.align 4\n\t.end/;
952                     } elsif ( $TargetPlatform =~ /^hppa/ ) {
953                         $c =~ s/^\s+ldil.*\n\s+ldo.*\n\s+bv.*\n(.*\n)?\s+\.EXIT/$1\t.EXIT/;
954                     } elsif ( $TargetPlatform =~ /^i386-/ ) {
955                         $c =~ s/^\tmovl \$${T_US}${symb}_fast\d+,\%edx\n\tjmp \*\%edx\n//;
956                         $c =~ s/^\tmovl \$${T_US}${symb}_fast\d+,\%eax\n\tjmp \*\%eax\n//;
957                     } elsif ( $TargetPlatform =~ /^mips-/ ) {
958                         $c =~ s/^\tjmp \$31,\(\$27\),0\n\t\.align 4\n\t\.end/\t.align 4\n\t.end/;
959                     } elsif ( $TargetPlatform =~ /^m68k-/ ) {
960                         $c =~ s/^\tjmp ${T_US}${symb}_fast\d+.*\n\tnop\n//;
961                         $c =~ s/^\tjmp ${T_US}${symb}_fast\d+.*\n//;
962                     } elsif ( $TargetPlatform =~ /^powerpc-|^rs6000-/ ) {
963                         $c =~ s/^\tb \.${T_US}${symb}_fast\d+\n//;
964                     } elsif ( $TargetPlatform =~ /^sparc-/ ) {
965                         $c =~ s/^\tcall ${T_US}${symb}_fast\d+,.*\n\tnop\n//;
966                         $c =~ s/^\tcall ${T_US}${symb}_fast\d+,.*\n(\t[a-z].*\n)/$1/;
967                     } else {
968                         print STDERR "$Pgm: mystery slow-fast dropthrough: $TargetPlatform\n";
969                     }
970                 }
971
972                 if ( $TargetPlatform !~ /^(alpha-|hppa|mips-)/ ) {
973                     # On alphas, hppa: no very good way to look for "dangling"
974                     # references to fast-entry point.
975                     # (questionable re hppa and mips...)
976                     print STDERR "still has jump to fast entry point:\n$c"
977                         if $c =~ /$TUS[@]?$symb[@]?_fast/; # NB: paranoia
978                 }
979
980                 print OUTASM $T_HDR_entry;
981
982                 &print_doctored($c, 1); # NB: the 1!!!
983
984                 $chkcat[$slowchk{$symb}] = 'DONE ALREADY';
985             }
986             
987             # FAST ENTRY POINT
988             if ( defined($fastchk{$symb}) ) {
989                 $c = $chk[$fastchk{$symb}];
990                 if ( ! defined($slowchk{$symb})
991                    # ToDo: the || clause can go once we're no longer
992                    # concerned about producing exactly the same output as before
993 #OLD:              || $TargetPlatform =~ /^(m68k|sparc|i386)-/
994                    ) {
995                     print OUTASM $T_HDR_fast;
996                 }
997                   if ($TargetPlatform =~ /^powerpc-|^rs6000-/) {
998                     local(@lbls) = split(/:/, $c);
999                     $fullname = $lbls[0];
1000                     $fullname =~ s/$T_MOVE_DIRVS//g;
1001                     if ( $fullname =~ /^[A-Z]/)
1002                        { print OUTASM "\t\.globl \.${fullname}\n";
1003                     } else {
1004                        print OUTASM "\t\.lglobl \.${fullname}\n"; #todo: rm - andre
1005                     };
1006                     $c =~ s/((.*\n)*)\t.long \S+, TOC\[tc0\], 0\n\.csect \.text\[PR\]\n((.*\n)*)/\1\3/;
1007                     $c = &mangle_powerpc_tailjump($c);
1008                   };
1009                 &print_doctored($c, 0);
1010                 $chkcat[$fastchk{$symb}] = 'DONE ALREADY';
1011             }
1012
1013         } elsif ( $chkcat[$i] eq 'vector'
1014                || $chkcat[$i] eq 'direct' ) { # do them in that order
1015             $symb = $chksymb[$i];
1016
1017             # VECTOR TABLE
1018             if ( defined($vectorchk{$symb}) ) {
1019                 print OUTASM $T_HDR_vector;
1020                 if ($TargetPlatform =~ /^powerpc-|^rs6000-/) { 
1021                   if ( $symb =~ /^[A-Z]/) {
1022                      print OUTASM "\t\.globl \.vtbl_${symb}\n";
1023                      print OUTASM "\t\.globl vtbl_${symb}\n";
1024                   };
1025                   $chk[$vectorchk{$symb}] =~ s/\.long (\S+)/\.long \.\1/g;
1026                   print OUTASM ".vtbl_${symb}:\n";
1027                   print OUTASM $chk[$vectorchk{$symb}];
1028                 } else {
1029                   print OUTASM &rev_tbl($symb, $chk[$vectorchk{$symb}], 0);
1030                 }
1031                 # direct return code will be put here!
1032                 $chkcat[$vectorchk{$symb}] = 'DONE ALREADY';
1033             }
1034
1035             # DIRECT RETURN
1036             if ( defined($directchk{$symb}) ) {
1037                 print OUTASM $T_HDR_direct;
1038                 if ($TargetPlatform =~ /^powerpc-|^rs6000-/) { 
1039                   ($p, $r) = split(/TOC\[tc0\], 0\n/, $chk[$directchk{$symb}]); 
1040                   &print_doctored($r, 0);
1041                   print OUTASM "\.csect ${symb}DirectReturn[DS]\n";     
1042                   print OUTASM "${p}TOC[tc0], 0\n";
1043                 } else {
1044                   &print_doctored($chk[$directchk{$symb}], 0);
1045                 }
1046                 $chkcat[$directchk{$symb}] = 'DONE ALREADY';
1047
1048             } elsif ( $TargetPlatform =~ /^alpha-/ ) {
1049                 # Alphas: the commented nop is for the splitter, to ensure
1050                 # that no module ends with a label as the very last
1051                 # thing.  (The linker will adjust the label to point
1052                 # to the first code word of the next module linked in,
1053                 # even if alignment constraints cause the label to move!)
1054
1055                 print OUTASM "\t# nop\n";
1056             }
1057             
1058         } elsif ( $chkcat[$i] eq 'toc' ) {
1059             # silly optimisation to print tocs, since they come in groups...
1060             print OUTASM $T_HDR_toc;
1061             local($j)   = $i;
1062             while ($chkcat[$j] eq 'toc')
1063               { print OUTASM $chk[$j];
1064                 $chkcat[$j] = 'DONE ALREADY';
1065                 $j++;
1066             }
1067             
1068         } else {
1069             &tidy_up_and_die(1,"$Pgm: unknown chkcat (ghc-asm: $TargetPlatform)\n$chkcat[$i]\n$chk[$i]\n");
1070         }
1071     }
1072
1073     print OUTASM $EXTERN_DECLS if $TargetPlatform =~ /^mips-/;
1074
1075     if ($TargetPlatform =~ /^powerpc-|^rs6000-/) { 
1076          print OUTASM ".csect .text[PR]\n_section_.text:\n.csect .data[RW]\n\t.long _section_.text\n"
1077     };
1078
1079     # finished
1080     close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n");
1081     close(INASM)  || &tidy_up_and_die(1,"Failed reading from $in_asmf\n");
1082 }
1083 \end{code}
1084
1085 \begin{code}
1086 sub mash_hppa_prologue { # OK, epilogue, too
1087     local($_) = @_;
1088
1089     # toss all prologue stuff
1090     s/^\s+\.ENTRY[^\0]*--- BEGIN ---/\t.ENTRY/;
1091
1092     # Lie about our .CALLINFO
1093     s/^\s+\.CALLINFO.*$/\t.CALLINFO NO_CALLS,NO_UNWIND/;
1094
1095     # Get rid of P'
1096
1097     s/LP'/L'/g;
1098     s/RP'/R'/g;
1099
1100     # toss all epilogue stuff
1101     s/^\s+--- END ---[^\0]*\.EXIT/\t.EXIT/;
1102
1103     # Sorry; we moved the _info stuff to the code segment.
1104     s/_info,DATA/_info,CODE/g;
1105
1106     return($_);
1107 }
1108 \end{code}
1109
1110 \begin{code}
1111 sub print_doctored {
1112     local($_, $need_fallthru_patch) = @_;
1113
1114     if ( $TargetPlatform !~ /^i386-/ 
1115       || ! /^\t[a-z]/ ) { # no instructions in here, apparently
1116         print OUTASM $_;
1117         return;
1118     }
1119     # OK, must do some x86 **HACKING**
1120
1121     local($entry_patch) = '';
1122     local($exit_patch)  = '';
1123     local($call_entry_patch)= '';
1124     local($call_exit_patch)     = '';
1125
1126 #OLD:   # first, convert calls to *very magic form*: (ToDo: document
1127     # for real!)  from
1128     #
1129     #   pushl $768
1130     #   call _?PerformGC_wrapper
1131     #   addl $4,%esp
1132     # to
1133     #   movl $768, %eax
1134     #   call _?PerformGC_wrapper
1135     #
1136     # The reason we do this now is to remove the apparent use of
1137     # %esp, which would throw off the "what patch code do we need"
1138     # decision.
1139     #
1140     # Special macros in ghc/includes/COptWraps.lh, used in
1141     # ghc/runtime/CallWrap_C.lc, are required for this to work!
1142     #
1143
1144     s/^\tpushl \$(\d+)\n\tcall ${T_DO_GC}\n\taddl \$4,\%esp\n/\tmovl \$$1,\%eax\n\tcall ${T_DO_GC}\n/go;
1145     s/^\tpushl \%eax\n\tcall ${T_DO_GC}\n\taddl \$4,\%esp\n/\tcall ${T_DO_GC}\n/go;
1146     s/^\tpushl \%edx\n\tcall ${T_DO_GC}\n\taddl \$4,\%esp\n/\tmovl \%edx,\%eax\n\tcall ${T_DO_GC}\n/go;
1147
1148 #=  if ( $StolenX86Regs <= 4 ) { # %ecx is ordinary reg
1149 #=      s/^\tpushl \%ecx\n\tcall ${T_DO_GC}\n\taddl \$4,\%esp\n/\tmovl \%ecx,\%eax\n\tcall ${T_DO_GC}\n/go;
1150 #=  }
1151
1152     # gotta watch out for weird instructions that
1153     # invisibly smash various regs:
1154     #   rep*    %ecx used for counting
1155     #   scas*   %edi used for destination index
1156     #   cmps*   %e[sd]i used for indices
1157     #   loop*   %ecx used for counting
1158     #
1159     # SIGH.
1160
1161     # We cater for:
1162     #  * use of STG reg [ nn(%ebx) ] where no machine reg avail
1163     #
1164     #  * GCC used an "STG reg" for its own purposes
1165     #
1166     #  * some secret uses of machine reg, requiring STG reg
1167     #    to be saved/restored
1168
1169     # The most dangerous "GCC uses" of an "STG reg" are when
1170     # the reg holds the target of a jmp -- it's tricky to
1171     # insert the patch-up code before we get to the target!
1172     # So here we change the jmps:
1173
1174     # --------------------------------------------------------
1175     # it can happen that we have jumps of the form...
1176     #   jmp *<something involving %esp>
1177     # or
1178     #   jmp <something involving another naughty register...>
1179     #
1180     # a reasonably-common case is:
1181     #
1182     #   movl $_blah,<bad-reg>
1183     #   jmp  *<bad-reg>
1184     #
1185     # which is easily fixed as:
1186     #
1187     # sigh! try to hack around it...
1188     #
1189
1190     if ($StolenX86Regs <= 2 ) { # YURGH! spurious uses of esi?
1191         s/^\tmovl (.*),\%esi\n\tjmp \*%esi\n/\tmovl $1,\%eax\n\tjmp \*\%eax\n/g;
1192         s/^\tjmp \*(-?\d*)\((.*\%esi.*)\)\n/\tmovl $2,\%eax\n\tjmp \*$1\(\%eax\)\n/g;
1193         s/^\tjmp \*\%esi\n/\tmovl \%esi,\%eax\n\tjmp \*\%eax\n/g;
1194         die "$Pgm: (mangler) still have jump involving \%esi!\n$_"
1195             if /(jmp|call) .*\%esi/;
1196     }
1197     if ($StolenX86Regs <= 3 ) { # spurious uses of edi?
1198         s/^\tmovl (.*),\%edi\n\tjmp \*%edi\n/\tmovl $1,\%eax\n\tjmp \*\%eax\n/g;
1199         s/^\tjmp \*(-?\d*)\((.*\%edi.*)\)\n/\tmovl $2,\%eax\n\tjmp \*$1\(\%eax\)\n/g;
1200         s/^\tjmp \*\%edi\n/\tmovl \%edi,\%eax\n\tjmp \*\%eax\n/g;
1201         die "$Pgm: (mangler) still have jump involving \%edi!\n$_"
1202             if /(jmp|call) .*\%edi/;
1203     }
1204 #=  if ($StolenX86Regs <= 4 ) { # spurious uses of ecx?
1205 #=      s/^\tmovl (.*),\%ecx\n\tjmp \*%ecx\n/\tmovl $1,\%eax\n\tjmp \*\%eax\n/g;
1206 #=      s/^\tjmp \*(-?\d*)\((.*\%ecx.*)\)\n/\tmovl $2,\%eax\n\tjmp \*$1\(\%eax\)\n/g;
1207 #=      s/^\tjmp \*\%ecx\n/\tmovl \%ecx,\%eax\n\tjmp \*\%eax\n/g;
1208 #=      die "$Pgm: (mangler) still have jump involving \%ecx!\n$_"
1209 #=          if /(jmp|call) .*\%ecx/;
1210 #=  }
1211
1212     # OK, now we can decide what our patch-up code is going to
1213     # be:
1214     if ( $StolenX86Regs <= 2
1215          && ( /32\(\%ebx\)/ || /\%esi/ || /^\tcmps/ ) ) { # R1 (esi)
1216         $entry_patch .= "\tmovl \%esi,32(\%ebx)\n";
1217         $exit_patch  .= "\tmovl 32(\%ebx),\%esi\n";
1218         # nothing for call_{entry,exit} because %esi is callee-save
1219     }
1220     if ( $StolenX86Regs <= 3
1221          && ( /64\(\%ebx\)/ || /\%edi/ || /^\t(scas|cmps)/ ) ) { # SpA (edi)
1222         $entry_patch .= "\tmovl \%edi,64(\%ebx)\n";
1223         $exit_patch  .= "\tmovl 64(\%ebx),\%edi\n";
1224         # nothing for call_{entry,exit} because %edi is callee-save
1225     }
1226 #=  if ( $StolenX86Regs <= 4
1227 #=       && ( /80\(\%ebx\)/ || /\%ecx/ || /^\t(rep|loop)/ ) ) { # Hp (ecx)
1228 #=      $entry_patch .= "\tmovl \%ecx,80(\%ebx)\n";
1229 #=      $exit_patch  .= "\tmovl 80(\%ebx),\%ecx\n";
1230 #=
1231 #=      $call_exit_patch  .= "\tmovl \%ecx,108(\%ebx)\n";
1232 #=      $call_entry_patch .= "\tmovl 108(\%ebx),\%ecx\n";
1233 #=      # I have a really bad feeling about this if we ever
1234 #=      # have a nested call...
1235 #=      # NB: should just hide it somewhere in the C stack.
1236 #=  }
1237     # --------------------------------------------------------
1238     # next, here we go with non-%esp patching!
1239     #
1240     s/^(\t[a-z])/$entry_patch$1/; # before first instruction
1241     s/^(\tcall .*\n(\taddl \$\d+,\%esp\n)?)/$call_exit_patch$1$call_entry_patch/g; # _all_ calls
1242
1243     # fix _all_ non-local jumps:
1244
1245     s/^\tjmp \*${T_X86_PRE_LLBL_PAT}/\tJMP___SL/go;
1246     s/^\tjmp ${T_X86_PRE_LLBL_PAT}/\tJMP___L/go;
1247
1248     s/^(\tjmp .*\n)/$exit_patch$1/g; # here's the fix...
1249
1250     s/^\tJMP___SL/\tjmp \*${T_X86_PRE_LLBL}/go;
1251     s/^\tJMP___L/\tjmp ${T_X86_PRE_LLBL}/go;
1252
1253     # fix post-PerformGC wrapper (re-)entries ???
1254
1255     if ($StolenX86Regs == 2 ) {
1256         die "ARGH! Jump uses \%esi or \%edi with -monly-2-regs:\n$_" 
1257             if /^\t(jmp|call) .*\%e(si|di)/;
1258 #=      die "ARGH! Jump uses \%esi, \%edi, or \%ecx with -monly-2-regs:\n$_" 
1259 #=          if /^\t(jmp|call) .*\%e(si|di|cx)/;
1260     } elsif ($StolenX86Regs == 3 ) {
1261         die "ARGH! Jump uses \%edi with -monly-3-regs:\n$_" 
1262             if /^\t(jmp|call) .*\%edi/;
1263 #=      die "ARGH! Jump uses \%edi or \%ecx with -monly-3-regs:\n$_" 
1264 #=          if /^\t(jmp|call) .*\%e(di|cx)/;
1265 #=  } elsif ($StolenX86Regs == 4 ) {
1266 #=      die "ARGH! Jump uses \%ecx with -monly-4-regs:\n$_" 
1267 #=          if /^\t(jmp|call) .*\%ecx/;
1268     }
1269
1270     # final peephole fixes
1271
1272     s/^\tmovl \%eax,36\(\%ebx\)\n\tjmp \*36\(\%ebx\)\n/\tmovl \%eax,36\(\%ebx\)\n\tjmp \*\%eax\n/;
1273 # the short form may tickle perl bug:
1274 #    s/^\tmovl \$${T_US}(.*),(\%e[abcd]x)\n\tjmp \*$2/\tjmp $T_US$1/g;
1275     s/^\tmovl \$${T_US}(.*),\%eax\n\tjmp \*\%eax/\tjmp $T_US$1/g;
1276     s/^\tmovl \$${T_US}(.*),\%ebx\n\tjmp \*\%ebx/\tjmp $T_US$1/g;
1277     s/^\tmovl \$${T_US}(.*),\%ecx\n\tjmp \*\%ecx/\tjmp $T_US$1/g;
1278     s/^\tmovl \$${T_US}(.*),\%edx\n\tjmp \*\%edx/\tjmp $T_US$1/g;
1279
1280     # Hacks to eliminate some reloads of Hp.  Worth about 5% code size.
1281     # We could do much better than this, but at least it catches about
1282     # half of the unnecessary reloads.
1283     # Note that these will stop working if either:
1284     #  (i) the offset of Hp from BaseReg changes from 80, or
1285     #  (ii) the register assignment of BaseReg changes from %ebx
1286
1287     s/^\tmovl 80\(\%ebx\),\%e.x\n\tmovl \$(.*),(-?[0-9]*)\(\%e.x\)\n\tmovl 80\(\%ebx\),\%e(.)x/\tmovl 80\(\%ebx\),\%e$3x\n\tmovl \$$1,$2\(\%e$3x\)/g;
1288
1289     s/^\tmovl 80\(\%ebx\),\%e(.)x\n\tmovl (.*),\%e(.)x\n\tmovl \%e$3x,(-?[0-9]*\(\%e$1x\))\n\tmovl 80\(\%ebx\),\%e$1x/\tmovl 80\(\%ebx\),\%e$1x\n\tmovl $2,\%e$3x\n\tmovl \%e$3x,$4/g;
1290
1291     s/^\tmovl 80\(\%ebx\),\%edx((\n\t(movl|addl) .*,((-?[0-9]*\(.*)|(\%e[abc]x)))+)\n\tmovl 80\(\%ebx\),\%edx/\tmovl 80\(\%ebx\),\%edx$1/g;
1292     s/^\tmovl 80\(\%ebx\),\%eax((\n\t(movl|addl) .*,((-?[0-9]*\(.*)|(\%e[bcd]x)))+)\n\tmovl 80\(\%ebx\),\%eax/\tmovl 80\(\%ebx\),\%eax$1/g;
1293
1294     # --------------------------------------------------------
1295     # that's it -- print it
1296     #
1297     #die "Funny jumps?\n$_" if /${T_X86_BADJMP}/o; # paranoia
1298
1299     print OUTASM $_;
1300
1301     if ( $need_fallthru_patch ) { # exit patch for end of slow entry code
1302         print OUTASM $exit_patch;
1303         # ToDo: make it not print if there is a "jmp" at the end
1304     }
1305 }
1306 \end{code}
1307
1308 \begin{code}
1309 sub init_FUNNY_THINGS {
1310     %KNOWN_FUNNY_THING = (
1311         "${T_US}CheckHeapCode${T_POST_LBL}", 1,
1312         "${T_US}CommonUnderflow${T_POST_LBL}", 1,
1313         "${T_US}Continue${T_POST_LBL}", 1,
1314         "${T_US}EnterNodeCode${T_POST_LBL}", 1,
1315         "${T_US}ErrorIO_call_count${T_POST_LBL}", 1,
1316         "${T_US}ErrorIO_innards${T_POST_LBL}", 1,
1317         "${T_US}IndUpdRetDir${T_POST_LBL}", 1,
1318         "${T_US}IndUpdRetV0${T_POST_LBL}", 1,
1319         "${T_US}IndUpdRetV1${T_POST_LBL}", 1,
1320         "${T_US}IndUpdRetV2${T_POST_LBL}", 1,
1321         "${T_US}IndUpdRetV3${T_POST_LBL}", 1,
1322         "${T_US}IndUpdRetV4${T_POST_LBL}", 1,
1323         "${T_US}IndUpdRetV5${T_POST_LBL}", 1,
1324         "${T_US}IndUpdRetV6${T_POST_LBL}", 1,
1325         "${T_US}IndUpdRetV7${T_POST_LBL}", 1,
1326         "${T_US}PrimUnderflow${T_POST_LBL}", 1,
1327         "${T_US}StackUnderflowEnterNode${T_POST_LBL}", 1,
1328         "${T_US}StdErrorCode${T_POST_LBL}", 1,
1329         "${T_US}UnderflowVect0${T_POST_LBL}", 1,
1330         "${T_US}UnderflowVect1${T_POST_LBL}", 1,
1331         "${T_US}UnderflowVect2${T_POST_LBL}", 1,
1332         "${T_US}UnderflowVect3${T_POST_LBL}", 1,
1333         "${T_US}UnderflowVect4${T_POST_LBL}", 1,
1334         "${T_US}UnderflowVect5${T_POST_LBL}", 1,
1335         "${T_US}UnderflowVect6${T_POST_LBL}", 1,
1336         "${T_US}UnderflowVect7${T_POST_LBL}", 1,
1337         "${T_US}UpdErr${T_POST_LBL}", 1,
1338         "${T_US}UpdatePAP${T_POST_LBL}", 1,
1339         "${T_US}WorldStateToken${T_POST_LBL}", 1,
1340         "${T_US}_Enter_Internal${T_POST_LBL}", 1,
1341         "${T_US}_PRMarking_MarkNextAStack${T_POST_LBL}", 1,
1342         "${T_US}_PRMarking_MarkNextBStack${T_POST_LBL}", 1,
1343         "${T_US}_PRMarking_MarkNextCAF${T_POST_LBL}", 1,
1344         "${T_US}_PRMarking_MarkNextGA${T_POST_LBL}", 1,
1345         "${T_US}_PRMarking_MarkNextRoot${T_POST_LBL}", 1,
1346         "${T_US}_PRMarking_MarkNextSpark${T_POST_LBL}", 1,
1347         "${T_US}_PRMarking_MarkNextEvent${T_POST_LBL}", 1,
1348         "${T_US}_PRMarking_MarkNextClosureInFetchBuffer${T_POST_LBL}", 1,
1349         "${T_US}_Scavenge_Forward_Ref${T_POST_LBL}", 1,
1350         "${T_US}__std_entry_error__${T_POST_LBL}", 1,
1351         "${T_US}_startMarkWorld${T_POST_LBL}", 1,
1352         "${T_US}resumeThread${T_POST_LBL}", 1,
1353         "${T_US}startCcRegisteringWorld${T_POST_LBL}", 1,
1354         "${T_US}startEnterFloat${T_POST_LBL}", 1,
1355         "${T_US}startEnterInt${T_POST_LBL}", 1,
1356         "${T_US}startPerformIO${T_POST_LBL}", 1,
1357         "${T_US}startStgWorld${T_POST_LBL}", 1,
1358         "${T_US}stopPerformIO${T_POST_LBL}", 1
1359     );
1360 }
1361 \end{code}
1362
1363 The following table reversal is used for both info tables and return
1364 vectors.  In both cases, we remove the first entry from the table,
1365 reverse the table, put the label at the end, and paste some code
1366 (that which is normally referred to by the first entry in the table)
1367 right after the table itself.  (The code pasting is done elsewhere.)
1368
1369 \begin{code}
1370 sub rev_tbl {
1371     local($symb, $tbl, $discard1) = @_;
1372
1373     local($before) = '';
1374     local($label) = '';
1375     local(@imports) = (); # hppa only
1376     local(@words) = ();
1377     local($after) = '';
1378     local(@lines) = split(/\n/, $tbl);
1379     local($i, $j); #local ($i, $extra, $words_to_pad, $j);
1380    
1381     # see comment in mangleAsm as to why this silliness is needed.
1382     local($TDOTWORD) = ${T_DOT_WORD};
1383     local($TDOTGLOBAL) = ${T_DOT_GLOBAL};
1384     local($TUS) = ${T_US};
1385     local($TPOSTLBL) = ${T_POST_LBL};
1386
1387     for ($i = 0; $i <= $#lines && $lines[$i] !~ /^\t$TDOTWORD\s+/o; $i++) {
1388         $label .= $lines[$i] . "\n",
1389             next if $lines[$i] =~ /^[A-Za-z0-9_]+_info$TPOSTLBL[@]?$/o
1390                  || $lines[$i] =~ /$TDOTGLOBAL/o
1391                  || $lines[$i] =~ /^$TUS[@]?vtbl_\S+$TPOSTLBL[@]?$/o;
1392
1393         $before .= $lines[$i] . "\n"; # otherwise...
1394     }
1395
1396     if ( $TargetPlatform !~ /^hppa/ ) {
1397         for ( ; $i <= $#lines && $lines[$i] =~ /^\t$TDOTWORD\s+/o; $i++) {
1398             push(@words, $lines[$i]);
1399         }
1400     } else { # hppa weirdness
1401         for ( ; $i <= $#lines && $lines[$i] =~ /^\s+\.(word|IMPORT)/; $i++) {
1402             if ($lines[$i] =~ /^\s+\.IMPORT/) {
1403                 push(@imports, $lines[$i]);
1404             } else {
1405                 # We don't use HP's ``function pointers''
1406                 # We just use labels in code space, like normal people
1407                 $lines[$i] =~ s/P%//;
1408                 push(@words, $lines[$i]);
1409             }
1410         }
1411     }
1412
1413     # now throw away the first word (entry code):
1414     shift(@words) if $discard1;
1415
1416 # Padding removed to reduce code size and improve performance on Pentiums.
1417 # Simon M. 13/4/96
1418     # for 486-cache-friendliness, we want our tables aligned
1419     # on 16-byte boundaries (.align 4).  Let's pad:
1420 #    $extra = ($#words + 1) % 4;
1421 #    $words_to_pad = ($extra == 0) ? 0 : 4 - $extra;
1422 #    for ($j = 0; $j < $words_to_pad; $j++) { push(@words, "\t${T_DOT_WORD} 0"); }
1423
1424     for (; $i <= $#lines; $i++) {
1425         $after .= $lines[$i] . "\n";
1426     }
1427
1428     # Alphas:If we have anonymous text (not part of a procedure), the
1429     # linker may complain about missing exception information.  Bleh.
1430     if ( $TargetPlatform =~ /^alpha-/ && $label =~ /^([A-Za-z0-9_]+):$/) {
1431         $before = "\t.ent $1\n" . $before;
1432         $after .= "\t.end $1\n";
1433     }
1434
1435     $tbl = $before
1436          . (($TargetPlatform !~ /^hppa/) ? '' : join("\n", @imports) . "\n")
1437          . join("\n", (reverse @words)) . "\n"
1438          . $label . $after;
1439
1440 #   print STDERR "before=$before\n";
1441 #   print STDERR "label=$label\n";
1442 #   print STDERR "words=",(reverse @words),"\n";
1443 #   print STDERR "after=$after\n";
1444
1445     $tbl;
1446 }
1447 \end{code}
1448
1449 \begin{code}
1450 sub mini_mangle_asm_i386 {
1451     local($in_asmf, $out_asmf) = @_;
1452
1453     &init_TARGET_STUFF();
1454
1455     # see mangleAsm comment
1456     local($TUS) = ${T_US};
1457     local($TPOSTLBL)=${T_POST_LBL};
1458
1459     open(INASM, "< $in_asmf")
1460         || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n");
1461     open(OUTASM,"> $out_asmf")
1462         || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n");
1463
1464     while (<INASM>) {
1465         print OUTASM;
1466
1467         next unless
1468             /^$TUS[@]?(PerformGC|StackOverflow|Yield|PerformReschedule)_wrapper$TPOSTLBL\n/o;
1469         print OUTASM "\tmovl \%esp, ${T_US}__temp_esp\n";
1470         print OUTASM "\tmovl \%eax, ${T_US}__temp_eax\n";
1471     }
1472
1473     # finished:
1474     close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n");
1475     close(INASM)  || &tidy_up_and_die(1,"Failed reading from $in_asmf\n");
1476 }
1477 \end{code}
1478
1479 The HP is a major nuisance.  The threaded code mangler moved info
1480 tables from data space to code space, but unthreaded code in the RTS
1481 still has references to info tables in data space.  Since the HP
1482 linker is very precise about where symbols live, we need to patch the
1483 references in the unthreaded RTS as well.
1484
1485 \begin{code}
1486 sub mini_mangle_asm_hppa {
1487     local($in_asmf, $out_asmf) = @_;
1488
1489     open(INASM, "< $in_asmf")
1490         || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n");
1491     open(OUTASM,"> $out_asmf")
1492         || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n");
1493
1494     while (<INASM>) {
1495         s/_info,DATA/_info,CODE/;   # Move _info references to code space
1496         s/P%_PR/_PR/;
1497         print OUTASM;
1498     }
1499
1500     # finished:
1501     close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n");
1502     close(INASM)  || &tidy_up_and_die(1,"Failed reading from $in_asmf\n");
1503 }
1504
1505 \end{code}
1506  
1507 \begin{code}
1508 sub mini_mangle_asm_powerpc {
1509     local($in_asmf, $out_asmf) = @_;
1510
1511     open(INASM, "< $in_asmf")
1512         || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n");
1513     open(OUTASM,"> $out_asmf")
1514         || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n");
1515
1516     while (<INASM>) {
1517         s/long _PRStart/long ._PRStart/;
1518         s/long _PRIn_/long ._PRIn_/;
1519         s/long _Dummy_(\S+)_entry/long ._Dummy_\1_entry/;
1520         s/long _PRMarking_MarkNextRoot\[DS\]/long ._PRMarking_MarkNextRoot/;
1521         s/long _PRMarking_MarkNextCAF\[DS\]/long ._PRMarking_MarkNextCAF/;
1522         s/long _PRMarking_MarkNextAStack\[DS\]/long ._PRMarking_MarkNextAStack/;
1523         s/long _PRMarking_MarkNextBStack\[DS\]/long ._PRMarking_MarkNextBStack/;
1524         print OUTASM;
1525     }
1526
1527     # finished:
1528     close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n");
1529     close(INASM)  || &tidy_up_and_die(1,"Failed reading from $in_asmf\n");
1530 }
1531
1532 sub mangle_powerpc_tailjump {
1533     local($c) = @_;
1534     local($maybe_more) = 1;
1535     while (($c =~ /\tlw?z? \d+,LC\.\.\d+\(2\)\n\tmtctr \d+\n\tbctr\n/) && $maybe_more) 
1536       { $maybe_more = 0;
1537         $lcsymb = $c;
1538         $lcsymb =~ s/(.*\n)*\tlw?z? \d+,LC\.\.(\d+)\(2\)\n\tmtctr \d+\n\tbctr\n(.*\n)*/\2/;
1539 # the checks for r1 and r2 are mostly paranoia...
1540         $r1 = $c;
1541         $r1 =~ s/(.*\n)*\tlw?z? (\d+),LC\.\.\d+\(2\)\n\tmtctr \d+\n\tbctr\n(.*\n)*/\2/;
1542         $r2 = $c;
1543         $r2 =~ s/(.*\n)*\tlw?z? \d+,LC\.\.(\d+)\(2\)\n\tmtctr (\d+)\n\tbctr\n(.*\n)*/\3/;
1544         if (r1 == r2)
1545           { $maybe_more = 1;
1546             $c =~ s/((.*\n)*)\tlw?z? \d+,LC\.\.\d+\(2\)\n\tmtctr \d+\n\tbctr\n((.*\n)*)/\1\tb $tocequiv{$lcsymb}\n\3/;
1547           }
1548       };
1549     $c;
1550 }
1551
1552 # make "require"r happy...
1553 1;
1554 \end{code}