Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
718 jacekm 1
/*
2
** Small-C Compiler -- Part 4 -- Back End.
3
** Copyright 1982, 1983, 1985, 1988 J. E. Hendrix
4
** Copyright 1998 H T Walheim
5
** All rights reserved.
6
*/
7
#include 
8
#include "cc.h"
9
 
10
/* #define DISOPT */       /* display optimizations values */
11
 
12
/*************************** externals ****************************/
13
 
14
extern char
15
  *cptr, *macn, *litq, *symtab, optimize, ssname[NAMESIZE];
16
 
17
extern int
18
  *stage, litlab, litptr, csp, output, oldseg, usexpr,
19
  *snext, *stail, *slast;
20
 
21
 
22
/***************** optimizer command definitions ******************/
23
 
24
             /*     --      p-codes must not overlap these */
25
#define any     0x00FF   /* matches any p-code */
26
#define _pop    0x00FE   /* matches if corresponding POP2 exists */
27
#define pfree   0x00FD   /* matches if pri register free */
28
#define sfree   0x00FC   /* matches if sec register free */
29
#define comm    0x00FB   /* matches if registers are commutative */
30
 
31
             /*     --      these digits are reserved for n */
32
#define go      0x0100   /* go n entries */
33
#define gc      0x0200   /* get code from n entries away */
34
#define gv      0x0300   /* get value from n entries away */
35
#define sum     0x0400   /* add value from nth entry away */
36
#define neg     0x0500   /* negate the value */
37
#define ife     0x0600   /* if value == n do commands to next 0 */
38
#define ifl     0x0700   /* if value <  n do commands to next 0 */
39
#define swv     0x0800   /* swap value with value n entries away */
40
#define topop   0x0900   /* moves |code and current value to POP2 */
41
 
42
#define p1      0x0001   /* plus 1 */
43
#define p2      0x0002   /* plus 2 */
44
#define p3      0x0003   /* plus 3 */
45
#define p4      0x0004   /* plus 4 */
46
#define m1      0x00FF   /* minus 1 */
47
#define m2      0x00FE   /* minus 2 */
48
#define m3      0x00FD   /* minus 3 */
49
#define m4      0x00FC   /* minus 4 */
50
 
51
#define PRI      0030    /* primary register bits */
52
#define SEC      0003    /* secondary register bits */
53
#define USES     0011    /* use register contents */
54
#define ZAPS     0022    /* zap register contents */
55
#define PUSHES   0100    /* pushes onto the stack */
56
#define COMMUTES 0200    /* commutative p-code */
57
 
58
/******************** optimizer command lists *********************/
59
 
60
int
61
  seq00[] = {0,ADD12,MOVE21,0,                       /* ADD21 */
62
             go|p1,ADD21,0},
63
 
64
  seq01[] = {0,ADD1n,0,                              /* rINC1 or rDEC1 ? */
65
             ifl|m2,0,ifl|0,rDEC1,neg,0,ifl|p3,rINC1,0,0},
66
 
67
  seq02[] = {0,ADD2n,0,                              /* rINC2 or rDEC2 ? */
68
             ifl|m2,0,ifl|0,rDEC2,neg,0,ifl|p3,rINC2,0,0},
69
 
70
  seq03[] = {0,rDEC1,PUTbp1,rINC1,0,                 /* SUBbpn or DECbp */
71
             go|p2,ife|p1,DECbp,0,SUBbpn,0},
72
 
73
  seq04[] = {0,rDEC1,PUTwp1,rINC1,0,                 /* SUBwpn or DECwp */
74
             go|p2,ife|p1,DECwp,0,SUBwpn,0},
75
 
76
  seq05[] = {0,rDEC1,PUTbm1,rINC1,0,                 /* SUB_m_ COMMAn */
77
             go|p1,SUB_m_,go|p1,COMMAn,go|m1,0},
78
 
79
  seq06[] = {0,rDEC1,PUTwm1,rINC1,0,                 /* SUB_m_ COMMAn */
80
             go|p1,SUB_m_,go|p1,COMMAn,go|m1,0},
81
 
82
  seq07[] = {0,GETw1m,GETw2n,ADD12,MOVE21,GETb1p,0,  /* GETw2m GETb1p */
83
             go|p4,gv|m3,go|m1,GETw2m,gv|m3,0},
84
 
85
  seq08[] = {0,GETw1m,GETw2n,ADD12,MOVE21,GETb1pu,0, /* GETw2m GETb1pu */
86
             go|p4,gv|m3,go|m1,GETw2m,gv|m3,0},
87
 
88
  seq09[] = {0,GETw1m,GETw2n,ADD12,MOVE21,GETw1p,0,  /* GETw2m GETw1p */
89
             go|p4,gv|m3,go|m1,GETw2m,gv|m3,0},
90
 
91
  seq10[] = {0,GETw1m,GETw2m,SWAP12,0,               /* GETw2m GETw1m */
92
             go|p2,GETw1m,gv|m1,go|m1,gv|m1,0},
93
 
94
  seq11[] = {0,GETw1m,MOVE21,0,                      /* GETw2m */
95
             go|p1,GETw2m,gv|m1,0},
96
 
97
  seq12[] = {0,GETw1m,PUSH1,pfree,0,                 /* PUSHm */
98
             go|p1,PUSHm,gv|m1,0},
99
 
100
  seq13[] = {0,GETw1n,PUTbm1,pfree,0,                /* PUT_m_ COMMAn */
101
             PUT_m_,go|p1,COMMAn,go|m1,swv|p1,0},
102
 
103
  seq14[] = {0,GETw1n,PUTwm1,pfree,0,                /* PUT_m_ COMMAn */
104
             PUT_m_,go|p1,COMMAn,go|m1,swv|p1,0},
105
 
106
  seq15[] = {0,GETw1p,PUSH1,pfree,0,                 /* PUSHp */
107
             go|p1,PUSHp,gv|m1,0},
108
 
109
  seq16[] = {0,GETw1s,GETw2n,ADD12,MOVE21,0,         /* GETw2s ADD2n */
110
             go|p3,ADD2n,gv|m2,go|m1,GETw2s,gv|m2,0},
111
 
112
  seq17[] = {0,GETw1s,GETw2s,SWAP12,0,               /* GETw2s GETw1s */
113
             go|p2,GETw1s,gv|m1,go|m1,GETw2s,gv|m1,0},
114
 
115
  seq18[] = {0,GETw1s,MOVE21,0,                      /* GETw2s */
116
             go|p1,GETw2s,gv|m1,0},
117
 
118
  seq19[] = {0,GETw2m,GETw1n,SWAP12,SUB12,0,         /* GETw1m SUB1n */
119
             go|p3,SUB1n,gv|m2,go|m1,GETw1m,gv|m2,0},
120
 
121
  seq20[] = {0,GETw2n,ADD12,0,                       /* ADD1n */
122
             go|p1,ADD1n,gv|m1,0},
123
 
124
  seq21[] = {0,GETw2s,GETw1n,SWAP12,SUB12,0,         /* GETw1s SUB1n */
125
             go|p3,SUB1n,gv|m2,go|m1,GETw1s,gv|m2,0},
126
 
127
  seq22[] = {0,rINC1,PUTbm1,rDEC1,0,                 /* ADDm_ COMMAn */
128
             go|p1,ADDm_,go|p1,COMMAn,go|m1,0},
129
 
130
  seq23[] = {0,rINC1,PUTwm1,rDEC1,0,                 /* ADDm_ COMMAn */
131
             go|p1,ADDm_,go|p1,COMMAn,go|m1,0},
132
 
133
  seq24[] = {0,rINC1,PUTbp1,rDEC1,0,                 /* ADDbpn or INCbp */
134
             go|p2,ife|p1,INCbp,0,ADDbpn,0},
135
 
136
  seq25[] = {0,rINC1,PUTwp1,rDEC1,0,                 /* ADDwpn or INCwp */
137
             go|p2,ife|p1,INCwp,0,ADDwpn,0},
138
 
139
  seq26[] = {0,MOVE21,GETw1n,SWAP12,SUB12,0,         /* SUB1n */
140
             go|p3,SUB1n,gv|m2,0},
141
 
142
  seq27[] = {0,MOVE21,GETw1n,comm,0,                 /* GETw2n comm */
143
             go|p1,GETw2n,0},
144
 
145
  seq28[] = {0,POINT1m,GETw2n,ADD12,MOVE21,0,        /* POINT2m_ PLUSn */
146
             go|p3,PLUSn,gv|m2,go|m1,POINT2m_,gv|m2,0},
147
 
148
  seq29[] = {0,POINT1m,MOVE21,pfree,0,               /* POINT2m */
149
             go|p1,POINT2m,gv|m1,0},
150
 
151
  seq30[] = {0,POINT1m,PUSH1,pfree,_pop,0,           /* ... POINT2m */
152
             topop|POINT2m,go|p2,0},
153
 
154
  seq31[] = {0,POINT1s,GETw2n,ADD12,MOVE21,0,        /* POINT2s */
155
             sum|p1,go|p3,POINT2s,gv|m3,0},
156
 
157
  seq32[] = {0,POINT1s,PUSH1,MOVE21,0,               /* POINT2s PUSH2 */
158
             go|p1,POINT2s,gv|m1,go|p1,PUSH2,go|m1,0},
159
 
160
  seq33[] = {0,POINT1s,PUSH1,pfree,_pop,0,           /* ... POINT2s */
161
             topop|POINT2s,go|p2,0},
162
 
163
  seq34[] = {0,POINT1s,MOVE21,0,                     /* POINT2s */
164
             go|p1,POINT2s,gv|m1,0},
165
 
166
  seq35[] = {0,POINT2m,GETb1p,sfree,0,               /* GETb1m */
167
             go|p1,GETb1m,gv|m1,0},
168
 
169
  seq36[] = {0,POINT2m,GETb1pu,sfree,0,              /* GETb1mu */
170
             go|p1,GETb1mu,gv|m1,0},
171
 
172
  seq37[] = {0,POINT2m,GETw1p,sfree,0,               /* GETw1m */
173
             go|p1,GETw1m,gv|m1,0},
174
 
175
  seq38[] = {0,POINT2m_,PLUSn,GETw1p,sfree,0,        /* GETw1m_ PLUSn */
176
             go|p2,gc|m1,gv|m1,go|m1,GETw1m_,gv|m1,0},
177
 
178
  seq39[] = {0,POINT2s,GETb1p,sfree,0,               /* GETb1s */
179
             sum|p1,go|p1,GETb1s,gv|m1,0},
180
 
181
  seq40[] = {0,POINT2s,GETb1pu,sfree,0,              /* GETb1su */
182
             sum|p1,go|p1,GETb1su,gv|m1,0},
183
 
184
  seq41[] = {0,POINT2s,GETw1p,PUSH1,pfree,0,         /* PUSHs */
185
             sum|p1,go|p2,PUSHs,gv|m2,0},
186
 
187
  seq42[] = {0,POINT2s,GETw1p,sfree,0,               /* GETw1s */
188
             sum|p1,go|p1,GETw1s,gv|m1,0},
189
 
190
  seq43[] = {0,PUSH1,any,POP2,0,                     /* MOVE21 any */
191
             go|p2,gc|m1,gv|m1,go|m1,MOVE21,0},
192
 
193
  seq44[] = {0,PUSHm,_pop,0,                         /* ... GETw2m */
194
             topop|GETw2m,go|p1,0},
195
 
196
  seq45[] = {0,PUSHp,any,POP2,0,                     /* GETw2p ... */
197
             go|p2,gc|m1,gv|m1,go|m1,GETw2p,gv|m1,0},
198
 
199
  seq46[] = {0,PUSHs,_pop,0,                         /* ... GETw2s */
200
             topop|GETw2s,go|p1,0},
201
 
202
  seq47[] = {0,SUB1n,0,                              /* rDEC1 or rINC1 ? */
203
             ifl|m2,0,ifl|0,rINC1,neg,0,ifl|p3,rDEC1,0,0};
204
 
205
#define HIGH_SEQ  47
206
int seq[HIGH_SEQ + 1];
207
setseq() {
208
  seq[ 0] = seq00;  seq[ 1] = seq01;  seq[ 2] = seq02;  seq[ 3] = seq03;
209
  seq[ 4] = seq04;  seq[ 5] = seq05;  seq[ 6] = seq06;  seq[ 7] = seq07;
210
  seq[ 8] = seq08;  seq[ 9] = seq09;  seq[10] = seq10;  seq[11] = seq11;
211
  seq[12] = seq12;  seq[13] = seq13;  seq[14] = seq14;  seq[15] = seq15;
212
  seq[16] = seq16;  seq[17] = seq17;  seq[18] = seq18;  seq[19] = seq19;
213
  seq[20] = seq20;  seq[21] = seq21;  seq[22] = seq22;  seq[23] = seq23;
214
  seq[24] = seq24;  seq[25] = seq25;  seq[26] = seq26;  seq[27] = seq27;
215
  seq[28] = seq28;  seq[29] = seq29;  seq[30] = seq30;  seq[31] = seq31;
216
  seq[32] = seq32;  seq[33] = seq33;  seq[34] = seq34;  seq[35] = seq35;
217
  seq[36] = seq36;  seq[37] = seq37;  seq[38] = seq38;  seq[39] = seq39;
218
  seq[40] = seq40;  seq[41] = seq41;  seq[42] = seq42;  seq[43] = seq43;
219
  seq[44] = seq44;  seq[45] = seq45;  seq[46] = seq46;  seq[47] = seq47;
220
  }
221
 
222
/***************** assembly-code strings ******************/
223
 
224
int code[PCODES];
225
 
226
/*
227
** First byte contains flag bits indicating:
228
**    the value in ax is needed (010) or zapped (020)
229
**    the value in bx is needed (001) or zapped (002)
230
*/
231
setcodes() {
232
  setseq();
233
  code[ADD12]   = "\211ADD EAX,EBX\15\n";
234
  code[ADD1n]   = "\010?ADD EAX,\15\n??";
235
  code[ADD21]   = "\211ADD EBX,EAX\15\n";
236
  code[ADD2n]   = "\010?ADD EBX,\15\n??";
237
  code[ADDbpn]  = "\001ADD BYTE [EBX],\15\n";
238
  code[ADDwpn]  = "\001ADD WORD [EBX],\15\n";
239
  code[ADDm_]   = "\000ADD ";
240
  code[ADDSP]   = "\000?ADD ESP,\15\n??";
241
  code[AND12]   = "\211AND EAX,EBX\15\n";
242
  code[ANEG1]   = "\010NEG EAX\15\n";
243
  code[ARGCNTn] = "\000?MOV CL,?XOR CL,CL?\15\n";
244
  code[ASL12]   = "\011MOV ECX,EAX\15\nMOV EAX,EBX\15\nSAL EAX,CL\15\n";
245
  code[ASR12]   = "\011MOV ECX,EAX\15\nMOV EAX,EBX\15\nSAR EAX,CL\15\n";
246
  code[CALL1]   = "\010CALL EAX\15\n";
247
  code[CALLm]   = "\020CALL \15\n";
248
  code[BYTE_]   = "\000 DB ";
249
  code[BYTEn]   = "\000 RESB \15\n";
250
  code[BYTEr0]  = "\000 TIMES  DB 0\15\n";
251
  code[COM1]    = "\010NOT EAX\15\n";
252
  code[COMMAn]  = "\000,\15\n";
253
  code[DBL1]    = "\010SHL EAX,1\15\n";
254
  code[DBL2]    = "\001SHL EBX,1\15\n";
255
  code[DECbp]   = "\001DEC BYTE [EBX]\15\n";
256
  code[DECwp]   = "\001DEC WORD [EBX]\15\n";
257
  code[DIV12]   = "\011CDQ\15\nIDIV EBX\15\n";                 /* see gen() */
258
  code[DIV12u]  = "\011XOR EDX,EDX\15\nDIV EBX\15\n";            /* see gen() */
259
 
260
  code[DWORD_]   = "\000 DD ";
261
  code[DWORDn]   = "\000 DD \15\n";
262
  code[DWORDr0]  = "\000 TIMES  DD 0\15\n";
263
 
264
  code[ENTER]   = "\100PUSH EBP\15\nMOV EBP,ESP\15\n";
265
  code[EQ10f]   = "\010OR EAX,EAX\15\nJE _\15\nJMP _\15\n_:\15\n";
266
  code[EQ12]    = "\211CALL __eq\15\n";
267
  code[GE10f]   = "\010OR EAX,EAX\15\nJGE _\15\nJMP _\15\n_:\15\n";
268
  code[GE12]    = "\011CALL __ge\15\n";
269
  code[GE12u]   = "\011CALL __uge\15\n";
270
  code[GETb1m]  = "\020MOVSX EAX,BYTE []\15\n";
271
  code[GETb1mu] = "\020MOVZX EAX,BYTE []\15\n";
272
  code[GETb1p]  = "\021MOVSX EAX,BYTE [EBX???]\15\n";       /* see gen() */
273
  code[GETb1pu] = "\021MOVZX EAX,BYTE [EBX???]\15\n"; /* see gen() */
274
  code[GETb1s]  = "\020MOVSX EAX,BYTE [EBP]\15\n";
275
  code[GETb1su] = "\020MOVZX EAX,BYTE [EBP]\15\n";
276
 
277
  code[GETd1m]  = "\020MOV EAX,[]\15\n";
278
  code[GETd1n]  = "\020?MOV EAX,?XOR EAX,EAX?\15\n";
279
  code[GETd1p]  = "\021MOV EAX, [EBX???]\15\n";            /* see gen() */
280
  code[GETd2n]  = "\002?MOV EBX,?XOR EBX,EBX?\15\n";
281
 
282
  code[GETw1m]  = "\020MOVSX EAX,WORD []\15\n";
283
  code[GETw1m_] = "\020MOVSX EAX,WORD []";
284
  code[GETw1n]  = "\020?MOV  EAX,?XOR EAX,EAX?\15\n";
285
  code[GETw1p]  = "\021MOVSX EAX, WORD [EBX???]\15\n";            /* see gen() */
286
  code[GETw1s]  = "\020MOVSX EAX, WORD [EBP]\15\n";
287
  code[GETw2m]  = "\002MOVSX EBX,WORD \15\n";
288
  code[GETw2n]  = "\002?MOV EBX,?XOR EBX,EBX?\15\n";
289
  code[GETw2p]  = "\021MOVSX EBX,WORD [EBX???]\15\n";
290
  code[GETw2s]  = "\002MOVSX EBX,WORD [EBP]\15\n";
291
  code[GT10f]   = "\010OR EAX,EAX\15\nJG _\15\nJMP _\15\n_:\15\n";
292
  code[GT12]    = "\010CALL __gt\15\n";
293
  code[GT12u]   = "\011CALL __ugt\15\n";
294
  code[INCbp]   = "\001INC BYTE [EBX]\15\n";
295
  code[INCwp]   = "\001INC WORD [EBX]\15\n";
296
  code[WORD_]   = "\000 DW ";
297
  code[WORDn]   = "\000 RESW \15\n";
298
  code[WORDr0]  = "\000 TIMES  DW 0\15\n";
299
  code[JMPm]    = "\000JMP _\15\n";
300
  code[LABm]    = "\000_:\15\n";
301
  code[LE10f]   = "\010OR EAX,EAX\15\nJLE _\15\nJMP _\15\n_:\15\n";
302
  code[LE12]    = "\011CALL __le\15\n";
303
  code[LE12u]   = "\011CALL __ule\15\n";
304
  code[LNEG1]   = "\010CALL __lneg\15\n";
305
  code[LT10f]   = "\010OR EAX,EAX\15\nJL _\15\nJMP _\15\n_:\15\n";
306
  code[LT12]    = "\011CALL __lt\15\n";
307
  code[LT12u]   = "\011CALL __ult\15\n";
308
  code[MOD12]   = "\011CDQ\15\nIDIV EBX\15\nMOV EAX,EDX\15\n";      /* see gen() */
309
  code[MOD12u]  = "\011XOR EDX,EDX\15\nDIV EBX\15\nMOV EAX,EDX\15\n"; /* see gen() */
310
  code[MOVE21]  = "\012MOV EBX,EAX\15\n";
311
  code[MUL12]   = "\211IMUL EBX\15\n";
312
  code[MUL12u]  = "\211MUL EBX\15\n";
313
  code[NE10f]   = "\010OR EAX,EAX\15\nJNE _\15\nJMP _\15\n_:\15\n";
314
  code[NE12]    = "\211CALL __ne\15\n";
315
  code[NEARm]   = "\000 DD _\15\n";
316
  code[OR12]    = "\211OR EAX,EBX\15\n";
317
  code[PLUSn]   = "\000?+??\15\n";
318
  code[POINT1l] = "\020MOV EAX,_+\15\n";
319
  code[POINT1m] = "\020MOV EAX,\15\n";
320
  code[POINT1s] = "\020LEA EAX,[EBP]\15\n";
321
  code[POINT2m] = "\002MOV EBX,\15\n";
322
  code[POINT2m_]= "\002MOV EBX,";
323
  code[POINT2s] = "\002LEA EBX,[EBP]\15\n";
324
  code[POP2]    = "\002POP EBX\15\n";
325
  code[PUSH1]   = "\110PUSH EAX\15\n";
326
  code[PUSH2]   = "\101PUSH EBX\15\n";
327
  code[PUSHm]   = "\100PUSH \15\n";
328
  code[PUSHp]   = "\100PUSH [EBX???]\15\n";
329
  code[PUSHs]   = "\100PUSH [EBP???]\15\n";
330
  code[PUT_m_]  = "\000MOV ";
331
  code[PUTbm1]  = "\010MOV BYTE [],AL\15\n";
332
  code[PUTbp1]  = "\011MOV [EBX],AL\15\n";
333
  code[PUTdm1]  = "\010MOV DWORD [],EAX\15\n";
334
  code[PUTdp1]  = "\011MOV [EBX],EAX\15\n";
335
  code[PUTwm1]  = "\010MOV WORD [],AX\15\n";
336
  code[PUTwp1]  = "\011MOV [EBX],AX\15\n";
337
  code[rDEC1]   = "\010#DEC EAX\15\n#";
338
  code[rDEC2]   = "\010#DEC EBX\15\n#";
339
  code[REFm]    = "\000_";
340
  code[RETURN]  = "\000?MOV ESP,EBP\15\n??POP EBP\15\nRET\15\n";
341
  code[rINC1]   = "\010#INC EAX\15\n#";
342
  code[rINC2]   = "\010#INC EBX\15\n#";
343
  code[SUB_m_]  = "\000SUB ";
344
  code[SUB12]   = "\011SUB EAX,EBX\15\n";                    /* see gen() */
345
  code[SUB1n]   = "\010?SUB EAX,\15\n??";
346
  code[SUBbpn]  = "\001SUB [EBX],\15\n";
347
  code[SUBwpn]  = "\001SUB [EBX],\15\n";
348
  code[SWAP12]  = "\011XCHG EAX,EBX\15\n";
349
  code[SWAP1s]  = "\012POP EBX\15\nXCHG EAX,EBX\15\nPUSH EBX\15\n";
350
  code[SWITCH]  = "\012CALL __switch\15\n";
351
  code[XOR12]   = "\211XOR EAX,EBX\15\n";
352
  }
353
 
354
/***************** code generation functions *****************/
355
 
356
/*
357
** print all assembler info before any code is generated
358
** and ensure that the segments appear in the correct order.
359
*/
360
header()  {
361
/*  outline("  .386");
362
  outline("  .MODEL FLAT");
363
*/  toseg(CODESEG);
364
 
365
/* - FASM
366
  outline("EXTERN __eq");
367
  outline("EXTERN __ne");
368
  outline("EXTERN __le");
369
  outline("EXTERN __lt");
370
  outline("EXTERN __ge");
371
  outline("EXTERN __gt");
372
  outline("EXTERN __ule");
373
  outline("EXTERN __ult");
374
  outline("EXTERN __uge");
375
  outline("EXTERN __ugt");
376
  outline("EXTERN __lneg");
377
  outline("EXTERN __switch");
378
*/
379
 
380
  /* outline("dw 0"); *//* force non-zero code pointers, word alignment */
381
  toseg(DATASEG);
382
  /* outline("dw 0"); *//* force non-zero data pointers, word alignment */
383
  }
384
 
385
/*
386
** print any assembler stuff needed at the end
387
*/
388
trailer()  {
389
  char *cp;
390
  cptr = STARTGLB;
391
  while(cptr < ENDGLB) {
392
    if(cptr[IDENT] == FUNCTION && cptr[CLASS] == AUTOEXT)
393
      external(cptr + NAME, 0, FUNCTION);
394
    cptr += SYMMAX;
395
    }
396
/*
397
  if((cp = findglb("main")) && cp[CLASS]==STATIC)
398
    external("_main", 0, FUNCTION);
399
*/
400
  toseg(NULL);
401
/* outline("END"); */
402
#ifdef DISOPT
403
    {
404
    int i, *count;
405
    printf(";opt   count\n");
406
    for(i = -1; ++i <= HIGH_SEQ; ) {
407
      count = seq[i];
408
      printf("; %2u   %5u\n", i, *count);
409
      }
410
    }
411
#endif
412
  }
413
 
414
/*
415
** remember where we are in the queue in case we have to back up.
416
*/
417
setstage(before, start) int *before, *start; {
418
  if((*before = snext) == 0)
419
    snext = stage;
420
  *start = snext;
421
  }
422
 
423
/*
424
** generate code in staging buffer.
425
*/
426
gen(pcode, value)
427
int pcode, value;
428
  {
429
    int newcsp;
430
    switch(pcode)
431
      {
432
	case GETb1pu:
433
	case GETb1p:
434
	case GETw1p:
435
	case GETd1p:
436
	  gen(MOVE21, 0);
437
	  break;
438
	case SUB12:
439
	case MOD12:
440
	case MOD12u:
441
	case DIV12:
442
	case DIV12u:
443
	  gen(SWAP12, 0);
444
	  break;
445
	case PUSH1:
446
#ifdef INT32
447
	  csp -= BPD;
448
#else
449
	  csp -= BPW;
450
#endif
451
	  break;
452
	case POP2:
453
#ifdef INT32
454
	  csp += BPD;
455
#else
456
	  csp += BPW;
457
#endif
458
	  break;
459
	case ADDSP:
460
	case RETURN:
461
	  newcsp = value;
462
	  value -= csp;
463
	  csp = newcsp;
464
      }
465
    if(snext == 0)
466
      {
467
	outcode(pcode, value);
468
	return;
469
      }
470
    if(snext >= slast)
471
      {
472
	error("staging buffer overflow");
473
	return;
474
      }
475
    snext[0] = pcode;
476
    snext[1] = value;
477
    snext += 2;
478
  }
479
 
480
/*
481
** dump the contents of the queue.
482
** If start = 0, throw away contents.
483
** If before != 0, don't dump queue yet.
484
*/
485
clearstage(before, start)
486
int *before, *start;
487
  {
488
    if(before)
489
      {
490
	snext = before;
491
	return;
492
      }
493
    if(start)
494
      dumpstage();
495
    snext = 0;
496
  }
497
 
498
/*
499
** dump the staging buffer
500
*/
501
dumpstage()
502
  {
503
    int i;
504
    stail = snext;
505
    snext = stage;
506
    while(snext < stail)
507
      {
508
	if(optimize)
509
	  {
510
restart:
511
	    i = -1;
512
	    while(++i <= HIGH_SEQ)
513
	      if(peep(seq[i]))
514
		{
515
#ifdef DISOPT
516
		  if(isatty(output))
517
		    fprintf(stderr, "                   optimized %2u\n", i);
518
#endif
519
		  goto restart;
520
		}
521
	  }
522
	outcode(snext[0], snext[1]);
523
	snext += 2;
524
      }
525
  }
526
 
527
/*
528
** change to a new segment
529
** may be called with NULL, CODESEG, or DATASEG
530
** With NASM the section names are case-sensitive
531
*/
532
toseg(newseg)
533
int newseg;
534
  {
535
    if(oldseg == newseg)
536
      return;
537
/*    if(oldseg == CODESEG)
538
      outline("_TEXT ENDS");
539
    else if(oldseg == DATASEG)
540
      outline("_DATA ENDS");  <-- */
541
 
542
/* - FASM
543
    if(newseg == CODESEG)
544
      {
545
	outline("SECTION .text");
546
      }
547
    else if(newseg == DATASEG)
548
      outline("SECTION .data");
549
*/
550
    oldseg = newseg;
551
  }
552
 
553
/*
554
** declare entry point
555
*/
556
public(ident) int ident;{
557
  if(ident == FUNCTION)
558
       toseg(CODESEG);
559
  else toseg(DATASEG);
560
/* - FASM
561
  outstr("GLOBAL ");
562
  outname(ssname);
563
*/
564
  newline();
565
  outname(ssname);
566
  if(ident == FUNCTION) {
567
    colon();
568
    newline();
569
    }
570
  }
571
 
572
/*
573
** declare external reference
574
*/
575
external(name, size, ident) char *name; int size, ident; {
576
  if(ident == FUNCTION)
577
       toseg(CODESEG);
578
  else toseg(DATASEG);
579
/* - FASM
580
  outstr("EXTERN ");
581
  outname(name);
582
/#  colon();
583
  outsize(size, ident);	<-- #/
584
  newline();
585
*/
586
  }
587
 
588
/*
589
** output the size of the object pointed to.
590
*/
591
outsize(size, ident) int size, ident;
592
  {
593
    /* why not size on FUNCTION and POINTER ? */
594
    if (ident == FUNCTION)
595
      outstr("NEAR");
596
    else if (ident == POINTER)
597
      outstr("DWORD");
598
    else if(size == 1)
599
      outstr("BYTE");
600
    else if(size == 2)
601
      outstr("WORD");
602
    else
603
      outstr("DWORD");
604
  }
605
 
606
/*
607
** point to following object(s)
608
*/
609
point() {
610
  outline(" DW $+2");
611
  }
612
 
613
/*
614
** dump the literal pool
615
*/
616
dumplits(size) int size;
617
{
618
  int j, k;
619
  k = 0;
620
  while (k < litptr)
621
    {
622
      if(size == 1)
623
	{
624
	  gen(BYTE_, NULL);
625
	}
626
      else if (size == 2)
627
	{
628
	  gen(WORD_, NULL);
629
	}
630
      else
631
	{
632
	  gen(DWORD_,NULL);
633
	}
634
      j = 10;
635
      while(j--)
636
	{
637
	  outdec(getint(litq + k, size));
638
	  k += size;
639
	  if(j == 0 || k >= litptr)
640
	    {
641
	      newline();
642
	      break;
643
	    }
644
	  fputc(',', output);
645
	}
646
    }
647
}
648
 
649
/*
650
** dump zeroes for default initial values
651
*/
652
dumpzero(size, count)
653
int size, count;
654
{
655
  if(count > 0)
656
    {
657
      if(size == 1)
658
	gen(BYTEr0, count);
659
      else if (size == 2)
660
	gen(WORDr0, count);
661
      else
662
	gen(DWORDr0, count);
663
    }
664
  }
665
 
666
/******************** optimizer functions ***********************/
667
 
668
/*
669
** Try to optimize sequence at snext in the staging buffer.
670
*/
671
peep(seq) int *seq; {
672
  int *next, *count, *pop, n, skip, tmp, reply;
673
  char c;
674
  next = snext;
675
  count = seq++;
676
  while(*seq) {
677
    switch(*seq) {
678
      case any:   if(next < stail)       break;      return (NO);
679
      case pfree: if(isfree(PRI, next))  break;      return (NO);
680
      case sfree: if(isfree(SEC, next))  break;      return (NO);
681
      case comm:  if(*next & COMMUTES)   break;      return (NO);
682
      case _pop:  if(pop = getpop(next)) break;      return (NO);
683
      default:    if(next >= stail || *next != *seq) return (NO);
684
      }
685
    next += 2; ++seq;
686
    }
687
 
688
  /****** have a match, now optimize it ******/
689
 
690
  *count += 1;
691
  reply = skip = NO;
692
  while(*(++seq) || skip) {
693
    if(skip) {
694
      if(*seq == 0) skip = NO;
695
      continue;
696
      }
697
    if(*seq >= PCODES) {
698
      c = *seq & 0xFF;            /* get low byte of command */
699
      n = c;                      /* and sign extend into n */
700
      switch(*seq & 0xFF00) {
701
        case ife:   if(snext[1] != n) skip = YES;  break;
702
        case ifl:   if(snext[1] >= n) skip = YES;  break;
703
        case go:    snext += (n<<1);               break;
704
        case gc:    snext[0] =  snext[(n<<1)];     goto done;
705
        case gv:    snext[1] =  snext[(n<<1)+1];   goto done;
706
        case sum:   snext[1] += snext[(n<<1)+1];   goto done;
707
        case neg:   snext[1] = -snext[1];          goto done;
708
        case topop: pop[0] = n; pop[1] = snext[1]; goto done;
709
        case swv:   tmp = snext[1];
710
                    snext[1] = snext[(n<<1)+1];
711
                    snext[(n<<1)+1] = tmp;
712
        done:       reply = YES;
713
                    break;
714
        }
715
      }
716
    else snext[0] = *seq;         /* set p-code */
717
    }
718
  return (reply);
719
  }
720
 
721
/*
722
** Is the primary or secondary register free?
723
** Is it zapped or unused by the p-code at pp
724
** or a successor?  If the primary register is
725
** unused by it still may not be free if the
726
** context uses the value of the expression.
727
*/
728
isfree(reg, pp) int reg, *pp; {
729
  char *cp;
730
  while(pp < stail) {
731
    cp = code[*pp];
732
    if(*cp & USES & reg) return (NO);
733
    if(*cp & ZAPS & reg) return (YES);
734
    pp += 2;
735
    }
736
  if(usexpr) return (reg & 001);   /* PRI => NO, SEC => YES at end */
737
  else       return (YES);
738
  }
739
 
740
/*
741
** Get place where the currently pushed value is popped?
742
** NOTE: Function arguments are not popped, they are
743
** wasted with an ADDSP.
744
*/
745
getpop(next) int *next; {
746
  char *cp;
747
  int level;  level = 0;
748
  while(YES) {
749
    if(next >= stail)                     /* compiler error */
750
      return 0;
751
    if(*next == POP2)
752
      if(level) --level;
753
      else return next;                   /* have a matching POP2 */
754
    else if(*next == ADDSP) {             /* after func call */
755
      if((level -= (next[1]>>LBPW)) < 0)
756
        return 0;
757
      }
758
    else {
759
      cp = code[*next];                   /* code string ptr */
760
      if(*cp & PUSHES) ++level;           /* must be a push */
761
      }
762
    next += 2;
763
    }
764
  }
765
 
766
/******************* output functions *********************/
767
 
768
colon() {
769
  fputc(':', output);
770
  }
771
 
772
newline() {
773
  fputc('\15', output);
774
  fputc(NEWLINE, output);
775
  }
776
 
777
/*
778
** output assembly code.
779
**
780
*/
781
outcode(pcode, value)
782
int pcode, value;
783
  {
784
    int part, skip, count;
785
    int byte_opt;
786
    char *cp, *back;
787
    int loc_label;
788
    part = back = 0;
789
    skip = NO;
790
    byte_opt = 0;
791
 
792
    cp = code[pcode] + 1;          /* skip 1st byte of code string */
793
 
794
#ifdef _MSC_VER
795
 
796
    switch (pcode)
797
      {
798
	case BYTE_:
799
	case BYTEn:
800
	case BYTEr0:
801
	case WORD_:
802
	case WORDn:
803
	case WORDr0:
804
	case DWORD_:
805
	case DWORDn:
806
	case DWORDr0:
807
	case REFm:
808
	case COMMAn:
809
	case PLUSn:
810
	  break;
811
 
812
	default:
813
 
814
	  dump_debug (pcode, value);
815
	  outtab ();
816
    }
817
#endif
818
 
819
    if (pcode == ADD1n)
820
      {
821
	if (value < 0)
822
	  {
823
	    pcode = SUB1n;
824
	    value = -value;
825
	  }
826
	if (value < 128)
827
	  {
828
	    byte_opt = 1;
829
	  }
830
      }
831
 
832
    while(*cp)
833
      {
834
	if(*cp == '<')
835
	  {
836
	    ++cp;                      /* skip to action code */
837
	    if(skip == NO)
838
	      switch(*cp)
839
		{
840
		  case 'm':
841
		    outname(value+NAME);
842
		    break; /* mem ref by label */
843
		  case 'n':
844
		    if (byte_opt)
845
		      {
846
			outstr ("BYTE ");
847
		      }
848
		    outdec(value);
849
		    break; /* numeric constant */
850
		  case 'o':
851
		    offset(value);
852
		    break; /* numeric constant */
853
		  case 'l':
854
		    outdec(litlab);
855
		    break; /* current literal label */
856
		  case 'g':	/* generate local label */
857
		    loc_label = getlabel ();
858
		    break;
859
		  case 'd':	/* dump local label */
860
		    outdec(loc_label);
861
		    break;
862
		}
863
	      cp += 2;                   /* skip past > */
864
	  }
865
	else if(*cp == '?')        /* ?..if value...?...if not value...? */
866
	  {
867
	    switch(++part)
868
	      {
869
		case 1:
870
		  if(value == 0)
871
		    skip = YES;
872
		  break;
873
		case 2:
874
		  skip = !skip;
875
		  break;
876
		case 3:
877
		  part = 0;
878
		  skip = NO;
879
		  break;
880
	      }
881
	    ++cp;                      /* skip past ? */
882
	  }
883
	else if(*cp == '#')
884
	  {        /* repeat #...# value times */
885
	    ++cp;
886
	    if(back == 0)
887
	      {
888
		if((count = value) < 1)
889
		  {
890
		    while(*cp && *cp++ != '#')
891
		      ;
892
		    continue;
893
		  }
894
		back = cp;
895
		continue;
896
	      }
897
	    if(--count > 0)
898
	      cp = back;
899
	    else
900
	      back = 0;
901
	  }
902
	else if(skip == NO)
903
	  fputc(*cp++, output);
904
	else
905
	  ++cp;
906
      }
907
  }
908
 
909
outdec(number)  int number; {
910
  int k, zs;
911
  char c, *q, *r;
912
  zs = 0;
913
  k = 1000000000;
914
 
915
#ifdef _MSC_VER
916
//  fprintf(output, "/* %d */", number);
917
#endif
918
 
919
  if(number < 0) {
920
    number = -number;
921
    fputc('-', output);
922
    }
923
 
924
  while (k >= 1) {
925
    q = 0;
926
    r = number;
927
    while(r >= k) {++q; r = r - k;}
928
    c = q + '0';
929
    if(c != '0' || k == 1 || zs) {
930
      zs = 1;
931
      fputc(c, output);
932
      }
933
    number = r;
934
    k /= 10;
935
    }
936
  }
937
 
938
offset(number)
939
int number;
940
{
941
  int k, zs;
942
  char c, *q, *r;
943
  zs = 0;
944
  k = 1000000000;
945
  if(number < 0) {
946
    number = -number;
947
    fputc('-', output);
948
    }
949
  else
950
    {
951
      fputc('+',output);
952
    }
953
 
954
  while (k >= 1) {
955
    q = 0;
956
    r = number;
957
    while(r >= k) {++q; r = r - k;}
958
    c = q + '0';
959
    if(c != '0' || k == 1 || zs) {
960
      zs = 1;
961
      fputc(c, output);
962
      }
963
    number = r;
964
    k /= 10;
965
    }
966
  }
967
 
968
outline(ptr)  char ptr[];  {
969
  outstr(ptr);
970
  newline();
971
  }
972
 
973
outname(ptr) char ptr[]; {
974
  outstr("_");
975
  while(*ptr >= ' ') fputc(*ptr++, output);
976
  }
977
 
978
outstr(ptr) char ptr[]; {
979
  while(*ptr == '\t' || *ptr >= ' ') fputc(*ptr++, output);
980
  }
981
 
982
outtab ()
983
  {
984
    fputc ('\t', output);
985
  }