Imported Upstream version 2.9.0
[debian/cc1111] / src / izt / gen.c
1 #include "izt.h"
2 #include "gen.h"
3
4 static struct
5   {
6     struct
7       {
8         lineNode *head;
9         lineNode *current;
10       }
11     lines;
12     struct
13       {
14         hTab *base;
15         hTab *proc;
16       }
17     htabs;
18   }
19 _G;
20
21 static void
22 _tidyUp (char *buf)
23 {
24   // Clean up the line so that it is 'prettier'.
25   if (*buf == ';')
26     {
27       // If this is a comment line (starts with a ';') then indent it.
28       // PENDING: The outputter does its own pretty print.  Disable for now.
29     }
30   else if (strchr (buf, ':'))
31     {
32       // Is a label - cant do anything.
33     }
34   else
35     {
36       /* Change the first (and probably only) ' ' to a tab so
37          everything lines up.
38        */
39       while (*buf)
40         {
41           if (*buf == ' ')
42             {
43               *buf = '\t';
44               return;
45             }
46           buf++;
47         }
48     }
49 }
50
51 void
52 iemit (const char *szFormat,...)
53 {
54   char buffer[1024];
55   va_list ap;
56
57   va_start (ap, szFormat);
58
59   tvsprintf (buffer, sizeof(buffer), szFormat, ap);
60
61   _tidyUp (buffer);
62
63   if (_G.lines.current == NULL)
64     {
65       _G.lines.head = newLineNode (buffer);
66       _G.lines.current = _G.lines.head;
67     }
68   else
69     {
70       _G.lines.current = connectLine (_G.lines.current, newLineNode (buffer));
71     }
72
73   // PENDING: Inline support.
74   //    _G.lines.current->isInline = inLine;
75 }
76
77 // Mapping between operand type and a friendly name.
78 typedef struct
79 {
80   const int op;
81   const char *name;
82 }
83 OPNAME;
84
85 static OPNAME _opnames[] =
86 {
87   {'!', "genNot"},
88   {'~', "genCpl"},
89   {UNARYMINUS, "genUminus"},
90   {IPUSH, "genIpush"},
91   {IPOP, "genIfx"},
92   {CALL, "genCall"},
93   {PCALL, "genPcall"},
94   {FUNCTION, "genFunction"},
95   {ENDFUNCTION, "genEndFunction"},
96   {RETURN, "genRet"},
97   {LABEL, "genLabel"},
98   {GOTO, "genGoto"},
99   {'+', "genPlus"},
100   {'-', "genMinus"},
101   {'*', "genMult"},
102   {'/', "genDiv"},
103   {'%', "genMod"},
104   {'>', "genCmpGt"},
105   {'<', "genCmpLt"},
106   {EQ_OP, "genCmpEq"},
107   {AND_OP, "genAndOp"},
108   {OR_OP, "genOrOp"},
109   {'^', "genXor"},
110   {'|', "genOr"},
111   {BITWISEAND, "genAnd"},
112   {INLINEASM, "genInline"},
113   {RRC, "genRRC"},
114   {RLC, "genRLC"},
115   {GETHBIT, "genHBIT"},
116   {LEFT_OP, "genLeftShift"},
117   {RIGHT_OP, "genRightShift"},
118   {GET_VALUE_AT_ADDRESS, "genPointerGet"},
119   {'=', "genAssign"},
120   {IFX, "genIfx"},
121   {ADDRESS_OF, "genAddrOf"},
122   {JUMPTABLE, "genJumpTab"},
123   {CAST, "genCast"},
124   {RECEIVE, "genReceive"},
125   {SEND, "addSet"},
126   {0, NULL}
127 };
128
129 // Possible return codes for a find matcher.
130 enum
131   {
132     FIND_LESS_THAN = -1,
133     // This element does match.
134     FIND_MATCH = 0,
135     FIND_GREATER_THAN = 1,
136     // This element doesnt match.
137     FIND_NO_MATCH = FIND_GREATER_THAN,
138     // This element marks the end of list.
139     FIND_EOL
140   };
141
142 // Limits the given integer to the find result numbers.
143 static int
144 _limitToFind (int i)
145 {
146   if (i < 0)
147     {
148       return FIND_LESS_THAN;
149     }
150   else if (i > 0)
151     {
152       return FIND_GREATER_THAN;
153     }
154   else
155     {
156       return FIND_MATCH;
157     }
158 }
159
160 // Matches an opname id to the given id.
161 static int
162 _opnamesMatcher (void *pthis, void *pkey)
163 {
164   OPNAME *name = pthis;
165
166   if (name->name == NULL)
167     {
168       return FIND_EOL;
169     }
170   else
171     {
172       return _limitToFind (name->op - *(int *) pkey);
173     }
174 }
175
176 // Find an element of an unordered list.
177 static void *
178 _find (void *base, size_t elemSize, void *pkey, int (*match) (void *pthis, void *pkey))
179 {
180   do
181     {
182       switch (match (base, pkey))
183         {
184         case FIND_MATCH:
185           return base;
186         case FIND_EOL:
187           return NULL;
188         case FIND_LESS_THAN:
189         case FIND_GREATER_THAN:
190           base = (char *) base + elemSize;
191           break;
192         default:
193           wassert (0);
194         }
195     }
196   while (1);
197 }
198
199 // Finds the friendly operation name for an op number.
200 static const char *
201 _findOpName (int op)
202 {
203   OPNAME *name = _find (_opnames, sizeof (*_opnames), &op, _opnamesMatcher);
204   if (name)
205     {
206       return name->name;
207     }
208   else
209     {
210       return NULL;
211     }
212 }
213
214 // PENDING
215 static bool
216 _isResultRemat (iCode * ic)
217 {
218   if (SKIP_IC (ic) || ic->op == IFX)
219     return 0;
220
221   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
222     {
223       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
224       if (sym->remat && !POINTER_SET (ic))
225         return 1;
226     }
227
228   return 0;
229 }
230
231 // Print out the generated lines.
232 static void
233 _printLines (void)
234 {
235   // Currently a holder function.  The Z80 needs some special mangling
236   // for bank support.
237   printLine (_G.lines.head, codeOutBuf);
238 }
239
240 void
241 izt_initEmitters (void)
242 {
243   _G.htabs.base = newHashTable (100);
244   _G.htabs.proc = newHashTable (100);
245
246   izt_initBaseEmitters (&_G.htabs.base);
247 }
248
249 static int
250 _emitterCompare (const void *p1, const void *p2)
251 {
252   wassert (p1);
253   wassert (p2);
254   return ((EMITTER *) p1)->op == ((EMITTER *) p2)->op;
255 }
256
257 static bool
258 _tryEmittingiCode (hTab * h, iCode * ic)
259 {
260   EMITTER key; // = {ic->op, NULL}; Borland C chokes on this; initialize below
261   EMITTER *found;
262
263   key.op = ic->op;
264   key.emit = NULL;
265
266   found = hTabFindByKey (h, ic->op, &key, _emitterCompare);
267
268   if (found)
269     {
270       found->emit (ic);
271       return TRUE;
272     }
273   else
274     {
275       return FALSE;
276     }
277 }
278
279 // Add a NULL terminated array of emitters into the given hash table.
280 void
281 izt_addEmittersToHTab (hTab ** into, EMITTER _base_emitters[])
282 {
283   while (_base_emitters->emit != NULL)
284     {
285       hTabAddItemLong (into, _base_emitters->op, _base_emitters, _base_emitters);
286       _base_emitters++;
287     }
288 }
289
290 void
291 izt_gen (iCode * iic)
292 {
293   iCode *ic = iic;
294   int cln = 0;
295
296   _G.lines.head = NULL;
297   _G.lines.current = NULL;
298
299   // No debug info support.
300
301   for (; ic; ic = ic->next)
302     {
303       const char *name;
304
305       // Print out the source file line number.
306       if (cln != ic->lineno)
307         {
308           iemit ("; %s %d", ic->filename, ic->lineno);
309           cln = ic->lineno;
310         }
311
312       if (ic->generated)
313         {
314           // Code has already been generated.  Skip.
315           continue;
316         }
317       if (_isResultRemat (ic))
318         {
319           // The code is spilt and remat. - no need to generate.
320           continue;
321         }
322
323       // Print the friendly name of the operation, if it has one.
324       name = _findOpName (ic->op);
325       if (name)
326         {
327           iemit ("; %s", name);
328         }
329       else
330         {
331           iemit ("; warning: unrecognised operation name for %u", ic->op);
332         }
333
334       fflush (stdout);
335       // Now actually call the code generator.
336       // The current processor handler gets first try.
337       if (_tryEmittingiCode (_G.htabs.proc, ic))
338         {
339           // Yay.
340         }
341       else if (_tryEmittingiCode (_G.htabs.base, ic))
342         {
343           // Base handler took it.
344         }
345       else
346         {
347           // None took it.  Warn the developer.
348           iemit ("; warning: no handler for code %u", ic->op);
349         }
350     }
351
352   // Pass the code through the peephole optimiser.
353   if (!options.nopeep)
354     {
355       peepHole (&_G.lines.head);
356     }
357
358   // And emit the remainder.
359   _printLines ();
360 }