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