blob: 03899e30d5f9083940c969e5c16610bc9bb229e2 [file] [log] [blame]
PulkoMandy17fc7592022-07-28 18:27:54 +02001/* EightThirtyTwo backend for vbcc,
2 based on the generic RISC backend
3
4 The CPU targeted by this backend, and the latest version, can be found at
5 https://github.com/robinsonb5/EightThirtyTwo
6
7*/
8
9// DONE - T2 no longer used at all - frees up a register for the main code generator
10
11// DONE Update the memcpy code to save/allocate registers if needed.
12// DONE Update the div code likewise.
13
14// Complete the work on object tracking. In particular take care of tracking an object vs
15// its address.
16// Also track via addressing-mode analysis whether or not it's valuable to save a value;
17// Values can also be saved to otherwise unused registers. (The compiler is almost certainly
18// already smart enough to make use of unused registers for this, however!)
19
20// DONE: eliminate unnecessary register shuffling for compare.
21
22// DONE: Implement block copying
23
24// DONE: Implement division / modulo using library code.
25// DONE: Mark registers as disposable if their contents are never used beyond the current op.
26
27// Look at ways of improving code efficiency. Look for situations where the output of one IC
28// becomes the input of another? Would make a big difference when registers are all in use.
29
30// Minus could be optimised for the in-register case.
31
32// DONE: Do we need to reserve two temp registers? Turns out one was sufficient, and giving
33// the code generator an extra one to play with helped a great deal.
34
35// Restrict byte and halfword storage to static and extern types, not stack-based variables.
36// (Having learned more, bytes and halfwords on the stack are fine, the complication is with
37// function parameters, which are promoted to int - thus the size modifier will be different
38// for parameters and local variables even though both live on the stack.)
39
40// DONE - Avoid moving registers for cmp and test when possible.
41
42// Condition code for test may well be already set by previous load.
43// Done for TEST, do the same for comparisons?
44
45// Deal with dereferencing in temp caching - can we avoid repeated setups in tmp, maybe using r0?
46
47
48#include "supp.h"
49
50#define DBGMSG 1
51
52static char FILE_[] = __FILE__;
53
54/* Public data that MUST be there. */
55
56/* Name and copyright. */
57char cg_copyright[] =
58 "vbcc EightThirtyTwo code-generator, (c) 2019/2020 by Alastair M. Robinson\nBased on the generic RISC example backend (c) 2001 by Volker Barthelmann";
59
60/* Commandline-flags the code-generator accepts:
61 0: just a flag
62 VALFLAG: a value must be specified
63 STRINGFLAG: a string can be specified
64 FUNCFLAG: a function will be called
65 apart from FUNCFLAG, all other versions can only be specified once */
66int g_flags[MAXGF] = { 0 };
67
68#define FLAG_PIC 0
69#define FLAG_LE 1
70#define FLAG_BE 2
71
72/* the flag-name, do not use names beginning with l, L, I, D or U, because
73 they collide with the frontend */
74/* 832-specific flags, "fpic" enables position independent code - name chosen to match gcc */
75char *g_flags_name[MAXGF] = { "fpic","el","eb" };
76
77char flag_832_bigendian;
78
79/* the results of parsing the command-line-flags will be stored here */
80union ppi g_flags_val[MAXGF] = { 0,0,0 };
81
82/* Alignment-requirements for all types in bytes. */
83zmax align[MAX_TYPE + 1];
84
85/* Alignment that is sufficient for every object. */
86zmax maxalign;
87
88/* CHAR_BIT for the target machine. */
89zmax char_bit;
90
91/* sizes of the basic types (in bytes) */
92zmax sizetab[MAX_TYPE + 1];
93
94/* Minimum and Maximum values each type can have. */
95/* Must be initialized in init_cg(). */
96zmax t_min[MAX_TYPE + 1];
97zumax t_max[MAX_TYPE + 1];
98zumax tu_max[MAX_TYPE + 1];
99
100/* Names of all registers. will be initialized in init_cg(),
101 register number 0 is invalid, valid registers start at 1 */
102char *regnames[MAXR + 1];
103
104/* The Size of each register in bytes. */
105zmax regsize[MAXR + 1];
106
107/* a type which can store each register. */
108struct Typ *regtype[MAXR + 1];
109
110/* regsa[reg]!=0 if a certain register is allocated and should */
111/* not be used by the compiler pass. */
112int regsa[MAXR + 1];
113
114/* Specifies which registers may be scratched by functions. */
115int regscratch[MAXR + 1];
116
117/* specifies the priority for the register-allocator, if the same
118 estimated cost-saving can be obtained by several registers, the
119 one with the highest priority will be used */
120int reg_prio[MAXR + 1];
121
122/* an empty reg-handle representing initial state */
123struct reg_handle empty_reg_handle = { 0, 0 };
124
125/* Names of target-specific variable attributes. */
126char *g_attr_name[] = { "__interrupt", "__ctor", "__dtor", "__weak", 0 };
127
128/****************************************/
129/* Private data and functions. */
130/****************************************/
131
132#define USE_COMMONS 0
133
134/* alignment of basic data-types, used to initialize align[] */
135/* In actual fact 832 has full load/store alignment so this is negotiable based on -speed / -size flags. */
136static long malign[MAX_TYPE + 1] = { 1, 1, 2, 4, 4, 4, 4, 8, 8, 1, 4, 1, 1, 1, 4, 1 };
137
138/* sizes of basic data-types, used to initialize sizetab[] */
139static long msizetab[MAX_TYPE + 1] = { 1, 1, 2, 4, 4, 8, 4, 8, 8, 0, 4, 0, 0, 0, 4, 0 };
140
141/* used to initialize regtyp[] */
142static struct Typ ltyp = { LONG }, ldbl = {
143DOUBLE}, lchar = {
144CHAR};
145
146/* macros defined by the backend */
147static char *marray[] = { "__section(x)=__vattr(\"section(\"#x\")\")",
148 "__EIGHTTHIRTYTWO__",
149 "__constructor(pri)=__vattr(\"ctor(\"#pri\")\")",
150 "__destructor(pri)=__vattr(\"dtor(\"#pri\")\")",
151 "__weak=__vattr(\"weak\")",
152 0
153};
154
155/* special registers */
156static int pc; /* Program counter */
157static int sp; /* Stackpointer */
158static int tmp;
159static int t1, t2; /* temporary gprs */
160static int f1, f2, f3; /* temporary fprs */
161static int loopid = 0; /* must be unique for every function in a compilation unit */
162
163
164/* sections */
165#define DATA 0
166#define BSS 1
167#define CODE 2
168#define RODATA 3
169#define SPECIAL 4
170
171//static long stack;
172static int section = -1, newobj;
173static char *codename = "\t.section\t.text";
174static char *dataname = "\t.section\t.data";
175static char *bssname = "\t.section\t.bss";
176static char *rodataname = "\t.section\t.rodata";
177static int sectionid=0;
178
179/* assembly-prefixes for labels and external identifiers */
180static char *labprefix = "l", *idprefix = "_";
181
182/* variables to keep track of the current stack-offset in the case of
183 a moving stack-pointer */
184static long pushed;
185static long notyetpopped;
186
187static long localsize, rsavesize, argsize;
188
189static int count_constantchunks(zmax v);
190static void emit_constanttotemp(FILE * f, zmax v);
191static void emit_statictotemp(FILE * f, char *lab, int suffix, int offset);
192static void emit_externtotemp(FILE * f, char *lab, int offset);
193static void emit_pcreltotemp2(FILE *f,struct obj *p);
194
195static void emit_prepobj(FILE * f, struct obj *p, int t, int reg, int offset);
196static int emit_objtoreg(FILE * f, struct obj *p, int t,int reg);
197
198/* calculate the actual current offset of an object relativ to the
199 stack-pointer; we use a layout like this:
200 ------------------------------------------------
201 | arguments to this function |
202 ------------------------------------------------
203 | return-address [size=4] |
204 ------------------------------------------------
205 | caller-save registers [size=rsavesize] |
206 ------------------------------------------------
207 | local variables [size=localsize] |
208 ------------------------------------------------
209 | arguments to called functions [size=argsize] |
210 ------------------------------------------------
211 All sizes will be aligned as necessary.
212 For a moving stack-pointer, the stack-pointer will usually point
213 to the bottom of the area for local variables, but will move while
214 arguments are put on the stack.
215
216 This is just an example layout. Other layouts are also possible.
217*/
218
219static long real_offset(struct obj *o)
220{
221 long off = 0;
222 if((o->flags&VAR) && isauto(o->v->storage_class))
223 off=zm2l(o->v->offset);
224// printf("Parameter offset: %d, localsize: %d, rsavesize: %d\n",off,localsize,rsavesize);
225 if (off < 0) {
226 /* function parameter */
227 off = localsize + rsavesize + 4 - off - zm2l(maxalign);
228 }
229 off += pushed;
230 off += notyetpopped;
231 off += zm2l(o->val.vmax);
232 return off;
233}
234
235
236static int isstackparam(struct obj *o)
237{
238 int result=0;
239// if(o->flags&VAR && o->flags&REG && o->reg==sp)
240// if(o->flags&(VAR|DREFOBJ)==VAR)
241 if((o->flags&VAR) && !(o->flags&REG))
242 {
243 if(isauto(o->v->storage_class))
244 {
245 long off = zm2l(o->v->offset);
246 if (off < 0)
247 result=1;
248 }
249 }
250 return(result);
251}
252
253/* Convenience function to determine whether we're assigning to 0(r6)
254 and can thus use a more efficient writing sequence. */
255
256int istopstackslot(struct obj *o)
257{
258 if(!o)
259 return(0);
260 if((o->flags&(VAR|REG|DREFOBJ))==VAR && o->v)
261 {
262 if(isauto(o->v->storage_class)
263 && real_offset(o)==0)
264 return(1);
265 }
266 return(0);
267}
268
269/* changes to a special section, used for __section() */
270static int special_section(FILE * f, struct Var *v)
271{
272 char *sec;
273 if (!v->vattr)
274 return 0;
275 sec = strstr(v->vattr, "section(");
276 if (!sec)
277 return 0;
278 sec += strlen("section(");
279 emit(f, "\t.section\t");
280 while (*sec && *sec != ')')
281 emit_char(f, *sec++);
282 emit(f, "\n");
283 if (f)
284 section = SPECIAL;
285 return 1;
286}
287
288/* Returns 1 if the symbol has weak linkage */
289static int isweak(struct Var *v)
290{
291 if (!v->vattr)
292 return 0;
293 if (strstr(v->vattr, "weak"))
294 return (1);
295 return 0;
296}
297
298/* Emits a pointer to a function in a .ctor or .dtor section for automatic setup/cleanup */
299static int ctor_dtor(FILE * f, struct Var *v)
300{
301 int dtor = 0;
302 char *sec;
303 if (!v->vattr)
304 return 0;
305 sec = strstr(v->vattr, "ctor(");
306 if (!sec) {
307 dtor = 1;
308 sec = strstr(v->vattr, "dtor(");
309 }
310 if (!sec)
311 return 0;
312 sec += strlen("ctor(");
313 emit(f, "\t%s.", dtor ? ".dtor .dtor" : ".ctor .ctor");
314 while (*sec && *sec != ')')
315 emit_char(f, *sec++);
316 emit(f, "\n\t.ref\t%s%s\n", idprefix, v->identifier);
317
318 return 1;
319}
320
321
322#define TEMP_TMP 0
323#define TEMP_T1 1
324struct tempobj
325{
326 struct obj o;
327 int reg;
328};
329struct tempobj tempobjs[2];
330
331void cleartempobj(FILE *f, int reg)
332{
333 int i;
334 if(reg==tmp) i=TEMP_TMP;
335 else if(reg==t1) i=TEMP_T1;
336 else return;
337// emit(f,"// clearing %s\n",regnames[reg]);
338
339 tempobjs[i].reg=0;
340}
341
342void settempkonst(FILE *f,int reg,int v)
343{
344 int i;
345 if(reg==tmp) i=TEMP_TMP;
346 else if(reg==t1) i=TEMP_T1;
347 else return;
348 tempobjs[i].reg=reg;
349 tempobjs[i].o.flags=KONST;
350 tempobjs[i].o.val.vlong=v;
351// emit(f,"// set %s to konst %d\n",regnames[reg],v);
352}
353
354
355// Add an adjustment due to postinc / predec to a cached object
356void adjtempobj(FILE *f,int reg,int offset)
357{
358 if(reg<=1)
359 tempobjs[reg].o.val.vlong+=offset;
360}
361
362
363// Store any passing value in tempobj records for optimisation.
364// FIXME - need to figure out VARADR semantics for stored objects.
365void settempobj(FILE *f,int reg,struct obj *o,int offset,int varadr)
366{
367 int i;
368 if(reg==tmp) i=TEMP_TMP;
369 else if(reg==t1) i=TEMP_T1;
370 else return;
371// if(reg==t1)
372// emit(f,"// Setting %s to %x (%x)\n",regnames[reg],o,o->v);
373 tempobjs[i].reg=reg;
374 tempobjs[i].o=*o;
375 tempobjs[i].o.val.vlong+=offset; // Account for any postinc / predec
376 if(varadr)
377 tempobjs[i].o.flags|=VARADR;
378}
379
380
381// Compare a pair of struct obj* for equivalence.
382// The first object should be the "live" object, the second one the cached object."
383int matchobj(FILE *f,struct obj *o1,struct obj *o2,int varadr)
384{
385 int result=1;
386 int flg=o1->flags;
387 if(varadr)
388 flg|=VARADR;
389// emit(f,"// comparing flags %x with %x\n",o1->flags, o2->flags);
390// if((o1->flags&~VARADR)!=(o2->flags&~VARADR))
391 // FIXME - need to figure out VARADR semantics for stored objects.
392 emit(f,"\t\t\t\t\t\t// matchobj comparing flags %d with %d\n",flg,o2->flags);
393 if(flg!=(o2->flags))
394 return(0);
395
396// emit(f,"// comparing regs %d with %d\n",o1->reg, o2->reg);
397 // If the register-based value is being dereferenced we would have to track
398 // the register itself being updated. Unless the value's in tmp using a cached
399 // version isn't a win anyway.
400 if((o1->flags&(REG|DREFOBJ)==REG) && (o1->reg==o2->reg))
401 return(1);
402
403 if(o1->flags&KONST)
404 {
405// emit(f,"\t\t\t\t\t\t// Comparing constants %x with %x\n",o1->val.vlong,o2->val.vlong);
406 if(o1->val.vlong == o2->val.vlong)
407 return(1);
408 else
409 { // Attempt fuzzy matching...
410 int d=o1->val.vlong-o2->val.vlong;
411 // Don't bother if we need fewer than four LIs to represent the value, or if we'd need more than 1 LI for the offset.
412 if(count_constantchunks(o1->val.vlong)<4 || count_constantchunks(d)>1)
413 {
414// emit(f,"\t\t\t\t\t\t// Gains from fuzzy matching too small, ignoring.\n");
415 return(0);
416 }
417 else
418 return(2);
419 }
420 }
421
422 if(!(o1->flags&VAR))
423 return(0); // Not a var? Can't do any more.
424
425 if(o1->v==0 || o2->v==0)
426 return(0);
427
428 if(o1->v == o2->v && o1->val.vlong == o2->val.vlong)
429 return(1);
430
431 if(!(flg&VARADR))
432 return(0); // Can only attempt fuzzy matching if this is a varadr
433
434 if(isauto(o1->v->storage_class) && isauto(o2->v->storage_class))
435 {
436 if(DBGMSG)
437 emit(f,"\t\t\t\t\t\t//auto: flags: %x, comparing %d, %d with %d, %d\n",
438 flg,o1->v->offset,o1->val.vlong, o2->v->offset,o2->val.vlong);
439 // Can't fuzzy match between parameters and vars on stack
440 if((o1->v->offset<0 && o2->v->offset>=0) || (o1->v->offset>=0 && o2->v->offset<0))
441 return(0);
442 if(o1->v->offset==o2->v->offset && o1->val.vlong==o2->val.vlong)
443 return(1);
444 if((o1->flags&DREFOBJ) || (o2->flags&DREFOBJ)) // Can't fuzzy match if we're dereferencing.
445 return(0);
446 return(2);
447 }
448
449 if(isextern(o1->v->storage_class) && isextern(o2->v->storage_class))
450 {
451 if(DBGMSG)
452 emit(f,"\t\t\t\t\t\t//extern: comparing %d with %d\n",o1->val.vlong, o2->val.vlong);
453 if(strcmp(o1->v->identifier,o2->v->identifier))
454 return(0);
455 if(o1->val.vlong==o2->val.vlong)
456 return(1);
457 if((o1->flags&DREFOBJ) || (o2->flags&DREFOBJ)) // Can't fuzzy match if we're dereferencing.
458 return(0);
459 return(2);
460 }
461
462 return(0);
463}
464
465
466int matchoffset(struct obj *o,struct obj *o2)
467{
468 if(o->flags&KONST)
469 return(o->val.vlong-o2->val.vlong);
470 if(isextern(o->v->storage_class))
471 return(o->val.vlong-o2->val.vlong);
472 if(isauto(o->v->storage_class))
473// return((o->val.vlong+real_offset(o))-(o2->val.vlong+real_offset(o2)));
474 return((o->val.vlong+o->v->offset)-(o2->val.vlong+o2->v->offset));
475 return(0);
476}
477
478
479void obsoletetempobj(FILE *f,int reg,struct obj *o,int varadr)
480{
481// emit(f,"\t\t\t\t\t// Attempting to obsolete obj\n");
482 if(tempobjs[0].reg==reg && matchobj(f,o,&tempobjs[0].o,varadr))
483 {
484 emit(f,"\t\t\t\t\t\t// Obsoleting tmp\n");
485 cleartempobj(f,tmp);
486 }
487 if(tempobjs[1].reg==reg && matchobj(f,o,&tempobjs[0].o,varadr))
488 {
489 emit(f,"\t\t\t\t\t\t// Obsoleting t1\n");
490 cleartempobj(f,t1);
491 }
492}
493
494
495// Check the tempobj records to see if the value we're interested in can be found in either.
496int matchtempobj(FILE *f,struct obj *o,int varadr,int preferredreg)
497{
498 int hit=0; // Hit will be 1 for an exact match, 2 for a near miss.
499// return(0); // Temporarily disable matching
500 if(tempobjs[0].reg && (hit=matchobj(f,o,&tempobjs[0].o,varadr)))
501 {
502// emit(f,"//match found - tmp\n");
503// printf("//match found - tmp\n");
504 if(hit==1)
505 return(tempobjs[0].reg);
506 else if(hit==2)
507 {
508 int offset=matchoffset(o,&tempobjs[0].o);
509 emit(f,"\t\t\t\t\t\t// Fuzzy match found against tmp.\n");
510 if(preferredreg==tmp)
511 {
512 emit(f,"\tmr\t%s\n",regnames[t1]);
513 emit(f,"\t.liconst\t%d\n",offset);
514 emit(f,"\taddt\t%s\n",regnames[t1]);
515 settempobj(f,t1,&tempobjs[0].o,0,0);
516 settempobj(f,tmp,o,0,varadr);
517 }
518 else
519 {
520 emit(f,"\tmr\t%s\n",regnames[preferredreg]);
521 emit(f,"\t.liconst\t%d\n",offset);
522 settempkonst(f,tmp,offset);
523 emit(f,"\tadd\t%s\n",regnames[preferredreg]);
524 settempobj(f,preferredreg,o,0,varadr);
525 }
526 return(preferredreg);
527// return(tempobjs[0].reg);
528 }
529 else
530 return(0);
531 }
532 else if(tempobjs[1].reg && (hit=matchobj(f,o,&tempobjs[1].o,varadr)))
533 {
534 // Temporarily disable t1 matching. FIXME - keep t1 records more up-to-date.
535// return(0);
536// emit(f,"//match found - t1\n");
537// printf("//match found - t1\n");
538 if(hit==1)
539 return(tempobjs[1].reg);
540 else if(hit==2)
541 {
542 int offset=matchoffset(o,&tempobjs[1].o);
543 if(DBGMSG)
544 emit(f,"\t\t\t\t\t\t//Fuzzy match found, offset: %d (varadr: %d)\n",offset,varadr);
545 // Fuzzy match against t1 - if target is t1 use add, otherwise use addt.
546 emit(f,"\t.liconst\t%d\n",offset);
547 if(preferredreg!=tempobjs[1].reg)
548 {
549 emit(f,"\taddt\t%s\n",regnames[tempobjs[1].reg]);
550 if(preferredreg!=tmp)
551 emit(f,"\tmr\t%s\n",regnames[preferredreg]);
552 settempobj(f,tmp,o,0,0);
553 settempobj(f,preferredreg,o,0,varadr);
554 }
555 else
556 {
557 emit(f,"\tadd\t%s\n",regnames[tempobjs[1].reg]);
558 settempkonst(f,tmp,offset);
559 settempobj(f,tempobjs[1].reg,o,0,varadr);
560 }
561 return(preferredreg);
562 }
563 return(0);
564 }
565 else
566 return(0);
567}
568
569
570int matchtempkonst(FILE *f,int k,int preferredreg)
571{
572// return(0); // Temporarily disable matching
573 struct obj o;
574 o.flags=KONST;
575 o.val.vlong=k;
576 return(matchtempobj(f,&o,0,preferredreg));
577}
578
579
580/* Generates code to store register r into memory object o. */
581
582static void store_reg(FILE * f, int r, struct obj *o, int type)
583{
584 // Need to take different types into account here.
585 if(DBGMSG)
586 emit(f, "\t\t\t\t\t\t// Store_reg to type 0x%x, flags 0x%x\n", type,o->flags);
587
588 type &= NQ; // Filter out unsigned, etc.
589 if((type==CHAR || type==SHORT) && isstackparam(o))
590 {
591 emit(f, "\t\t\t\t\t\t// Promoting storage size of stack parameter to int\n");
592 type=INT;
593 }
594
595 switch (type) {
596 case CHAR:
597 emit_prepobj(f, o, type & NQ, tmp, 0);
598 emit(f, "\texg\t%s\n", regnames[r]);
599 emit(f, "\tstbinc\t%s\t//WARNING - pointer / reg not restored, might cause trouble!\n", regnames[r]);
600 cleartempobj(f,tmp);
601 cleartempobj(f,r);
602 break;
603 case SHORT:
604 emit_prepobj(f, o, type & NQ, tmp, 0);
605 emit(f, "\texg\t%s\n", regnames[r]);
606 emit(f, "\thlf\n\tst\t%s\n", regnames[r]);
607 cleartempobj(f,tmp);
608 cleartempobj(f,r);
609 break;
610 case INT:
611 case LONG:
612 case POINTER:
613 // if o is a reg, can store directly.
614 if ((o->flags & (REG | DREFOBJ)) == (REG | DREFOBJ)) {
615 emit(f, "\tmt\t%s\n", regnames[r]);
616 emit(f, "\tst\t%s\n", regnames[o->reg]);
617// settempobj(f,r,o,0,0);
618 if((type&NQ)!=INT || (type & VOLATILE) || (type & PVOLATILE))
619 {
620 emit(f,"\t// Volatile, or not int - not caching\n");
621 cleartempobj(f,r);
622 }
623 else
624 settempobj(f,r,o,0,0); // FIXME - is this correct?
625 settempobj(f,tmp,o,0,0); // FIXME - is this correct?
626 } else {
627 if(o->flags & DREFOBJ) { // Can't use the offset / stmpdec trick for dereferenced objects.
628 // FIXME, not strictly true - could use it for dereferenced constants
629 emit_prepobj(f, o, type & NQ, tmp, 0);
630 emit(f, "\texg\t%s\n", regnames[r]);
631 emit(f, "\tst\t%s\n", regnames[r]);
632 if(r==t1 || (o->am && o->am->disposable))
633 emit(f, "\t\t\t\t\t\t// WARNING - Object is disposable, not bothering to undo exg - check correctness\n");
634 else
635 emit(f, "\texg\t%s\n", regnames[r]);
636 cleartempobj(f,tmp);
637 cleartempobj(f,r);
638 }
639 else {
640 emit_prepobj(f, o, type & NQ, tmp, 4); // stmpdec predecrements, so need to add 4!
641 emit(f, "\tstmpdec\t%s\n \t\t\t\t\t\t// WARNING - check that 4 has been added.\n", regnames[r]);
642 adjtempobj(f,tmp,-4);
643// cleartempobj(f,tmp);
644 if((type&NQ)!=INT || (type & VOLATILE) || (type & PVOLATILE))
645 {
646 emit(f,"\t// Volatile, or not int - not caching\n");
647 cleartempobj(f,r);
648 }
649 else
650 settempobj(f,r,o,0,0); // FIXME - is this correct?
651 }
652 }
653 break;
654 case LLONG:
655 if ((o->flags & (REG | DREFOBJ)) == (REG | DREFOBJ)) {
656 emit_prepobj(f, o, type & NQ, tmp, 0);
657 printf("store_reg: storing long long to dereferenced register\n");
658 emit(f,"//FIXME - need to store 64-bits\n");
659 ierror(0);
660 }
661 else {
662 //
663 printf("store_reg: storing long long in %s to reg\n",regnames[r]);
664 ierror(0);
665 }
666 break;
667 default:
668 printf("store_reg: unhandled type 0x%x\n", type);
669 ierror(0);
670 break;
671 }
672}
673
674
675/* Yields log2(x)+1 or 0. */
676static long pof2(zumax x)
677{
678 zumax p;
679 int ln = 1;
680 p = ul2zum(1L);
681 while (ln <= 32 && zumleq(p, x)) {
682 if (zumeqto(x, p))
683 return ln;
684 ln++;
685 p = zumadd(p, p);
686 }
687 return 0;
688}
689
690
691static int availreg()
692{
693 int i;
694 for(i=FIRST_GPR+RESERVED_GPRS;i<(LAST_GPR-1);++i)
695 if(regs[i]==0)
696 return(i);
697 return(0);
698}
699
700
701static struct IC *preload(FILE *, struct IC *,int stacksubst);
702
703static void function_top(FILE *, struct Var *, long);
704static int function_bottom(FILE * f, struct Var *, long,int);
705
706#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
707#define involvesreg(x) ((p->x.flags&(REG))==REG)
708#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
709
710static int q1reg, q2reg, zreg;
711
712static char *ccs[] = { "EQ", "NEQ", "SLT", "GE", "LE", "SGT", "EX", "" };
713static char *logicals[] = { "or", "xor", "and" };
714
715static char *arithmetics[] = { "shl", "shr", "add", "sub", "mul", "(div)", "(mod)" };
716
717/* Does some pre-processing like fetching operands from memory to
718 registers etc. */
719static struct IC *preload(FILE * f, struct IC *p,int stacksubst)
720{
721 int r;
722
723 if(stacksubst)
724 {
725 if(istopstackslot(&p->q1))
726 {
727 p->q1.reg=sp;
728 p->q1.flags|=REG|DREFOBJ;
729 }
730
731 if(istopstackslot(&p->q2))
732 {
733 p->q2.reg=sp;
734 p->q2.flags|=REG|DREFOBJ;
735 }
736
737 if(istopstackslot(&p->z))
738 {
739 p->z.reg=sp;
740 p->z.flags|=REG|DREFOBJ;
741 }
742 }
743
744 if (involvesreg(q1))
745 q1reg = p->q1.reg;
746 else
747 q1reg = 0;
748
749 if (involvesreg(q2))
750 q2reg = p->q2.reg;
751 else
752 q2reg = 0;
753
754 if (isreg(z)) {
755 zreg = p->z.reg;
756 } else {
757 if (ISFLOAT(ztyp(p)))
758 zreg = f1;
759 else
760 zreg = t1;
761 }
762
763 return p;
764}
765
766/* Determine whether the register we're about to write to will merely be passed to SetReturn.
767 If so, return 1, and convert the SetReturn IC to NOP */
768int next_setreturn(struct IC *p,int reg)
769{
770 int result=0;
771 struct IC *p2=p->next;
772 while(p2 && p2->code==FREEREG)
773 p2=p2->next;
774 if(p2 && p2->code==SETRETURN && (p2->q1.flags&(REG|DREFOBJ))==REG && p2->q1.reg==reg)
775 {
776 p2->code=NOP;
777 result=1;
778 }
779 return(result);
780}
781
782
783int consecutiveaccess(struct IC *p,struct IC *p2)
784{
785 if(!p || !p2)
786 return(0);
787// printf("Flags %x, %x\n",p->z.flags,p2->z.flags);
788 if(((p->z.flags&(VAR|DREFOBJ))==VAR) && ((p2->z.flags&(VAR|DREFOBJ))==VAR))
789 {
790 int result=real_offset(&p2->z)-real_offset(&p->z);
791// printf("Got two vars\n");
792 if(strcmp(p->z.v->identifier,p2->z.v->identifier))
793 return(0);
794 if(isstatic(p->z.v->storage_class) && isstatic(p->z.v->storage_class))
795 {
796// printf("Both static - dif %d\n",result);
797 return(result);
798 }
799 if(isextern(p->z.v->storage_class) && isextern(p->z.v->storage_class))
800 {
801// printf("Both extern - dif %d\n",result);
802 return(result);
803 }
804 }
805 return(0);
806}
807
808/* save the result (in temp) into p->z */
809/* Guaranteed not to touch t1/t2 unless nominated */
810/* or followed by a SetReturn IC. */
811void save_temp(FILE * f, struct IC *p, int treg)
812{
813 int type = ztyp(p) & NQ;
814 if(DBGMSG)
815 emit(f, "\t\t\t\t\t\t// (save temp)");
816
817 if (isreg(z)) {
818 int target=p->z.reg;
819 if(DBGMSG)
820 emit(f, "isreg\n");
821 if(next_setreturn(p,target))
822 target=t1;
823 emit(f, "\tmr\t%s\n", regnames[target]);
824 } else {
825 if ((p->z.flags & DREFOBJ) && (p->z.flags & REG))
826 treg = p->z.reg;
827 else if(isstackparam(&p->z) && !(p->z.flags & DREFOBJ))
828 type=INT;
829
830 if(DBGMSG)
831 emit(f, "store type %x\n",type);
832
833 switch (type) {
834 case CHAR:
835 if (p->z.am && p->z.am->type == AM_POSTINC)
836 {
837 emit(f, "\tstbinc\t%s\n", regnames[treg]);
838 adjtempobj(f,treg,1);
839 }
840 else if ((p->z.am && p->z.am->disposable)
841 || (treg == t1))
842 {
843 emit(f, "\tstbinc\t%s\n\t\t\t\t\t\t//Disposable, postinc doesn't matter.\n", regnames[treg]);
844 adjtempobj(f,treg,1);
845 }
846 else
847 emit(f, "\tbyt\n\tst\t%s\n", regnames[treg]);
848 break;
849 case SHORT:
850 emit(f, "\thlf\n\tst\t%s\n", regnames[treg]);
851 break;
852 case INT:
853 case LONG:
854 case POINTER:
855// // Would need to adjust the pointer at the setup stage since we're predecrementing
856// if (consecutiveaccess(p,p->next)==-4 || (p->z.am && p->z.am->type == AM_PREDEC))
857// {
858// emit(f, "\tstdec\t%s\n", regnames[treg]);
859// adjtempobj(f,treg,-4);
860// }
861 if (consecutiveaccess(p,p->next)==4 || (p->z.am && p->z.am->type == AM_POSTINC))
862 {
863 emit(f, "\tstinc\t%s\n", regnames[treg]);
864 adjtempobj(f,treg,4);
865 }
866 else
867 emit(f, "\tst\t%s\n", regnames[treg]);
868 break;
869 default:
870 printf("save_temp - type %d not yet handled\n", ztyp(p));
871 emit(f,"\t\t\t\t\t\t// FIXME - save_temp doesn't support size\n");
872 break;
873 }
874 }
875 if(DBGMSG)
876 emit(f, "\t\t\t\t\t\t//save_temp done\n");
877}
878
879/* save the result (in zreg) into p->z */
880void save_result(FILE * f, struct IC *p)
881{
882 if(DBGMSG)
883 emit(f, "\t\t\t\t\t\t// (save result) ");
884 if (isreg(z)) {
885 if(DBGMSG)
886 emit(f, "// isreg\n");
887 if (p->z.reg != zreg)
888 {
889 emit(f, "\tmt\t%s\n\tmr\t%s\n", regnames[zreg], regnames[p->z.reg]);
890 settempobj(f,tmp,&p->z,0,0);
891 settempobj(f,p->z.reg,&p->z,0,0);
892 }
893 }
894 else
895 {
896 emit(f, "// not reg\n");
897 store_reg(f,zreg,&p->z,ztyp(p));
898 }
899 return;
900}
901
902#include "addressingmodes.c"
903#include "tempregs.c"
904#include "inlinememcpy.c"
905#include "libcalls.c"
906
907/* generates the function entry code */
908static void function_top(FILE * f, struct Var *v, long offset)
909{
910 int i;
911 int regcount = 0;
912
913 cleartempobj(f,tmp);
914 cleartempobj(f,t1);
915
916 if(DBGMSG)
917 {
918 emit(f, "\t//registers used:\n");
919 for (i = FIRST_GPR+RESERVED_GPRS; i <= LAST_GPR; ++i) {
920 emit(f, "\t\t//%s: %s\n", regnames[i], regused[i] ? "yes" : "no");
921 if (regused[i] && (i >= (FIRST_GPR+SCRATCH_GPRS+RESERVED_GPRS)) && (i <= LAST_GPR - 2))
922 ++regcount;
923 }
924 }
925
926// Emit ctor / dtor tables
927 ctor_dtor(f, v);
928
929 rsavesize = 0;
930 if (!special_section(f, v)) {
931 emit(f, "\t.section\t.text.%x\n", sectionid);
932 section=CODE;
933 ++sectionid;
934 }
935 if (v->storage_class == EXTERN) {
936 if ((v->flags & (INLINEFUNC | INLINEEXT)) != INLINEFUNC) {
937 if (isweak(v))
938 emit(f, "\t.weak\t%s%s\n", idprefix, v->identifier);
939 else
940 emit(f, "\t.global\t%s%s\n", idprefix, v->identifier);
941 }
942 emit(f, "%s%s:\n", idprefix, v->identifier);
943 } else
944 emit(f, "%s%ld:\n", labprefix, zm2l(v->offset));
945
946 if (regcount < 3) {
947 emit(f, "\tstdec\t%s\n", regnames[sp]);
948 for (i = FIRST_GPR + SCRATCH_GPRS; i <= LAST_GPR - 3; ++i) {
949 if (regused[i] && !regscratch[i]) {
950 emit(f, "\tmt\t%s\n\tstdec\t%s\n", regnames[i], regnames[sp]);
951 rsavesize += 4;
952 }
953 }
954 } else {
955 emit(f, "\texg\t%s\n\tstmpdec\t%s\n", regnames[sp], regnames[sp]);
956 for (i = FIRST_GPR + SCRATCH_GPRS; i <= LAST_GPR - 3; ++i) {
957 if (regused[i] && !regscratch[i]) {
958 emit(f, "\tstmpdec\t%s\n", regnames[i]);
959 rsavesize += 4;
960 }
961 }
962 emit(f, "\texg\t%s\n", regnames[sp]);
963 }
964
965 // FIXME - Allow the stack to float, in the hope that we can use stdec to adjust it.
966
967 if ((offset == 4) && optsize)
968 emit(f, "\tstdec\tr6\t// shortest way to decrement sp by 4\n");
969 else if (offset) {
970 emit_constanttotemp(f, -offset);
971 emit(f, "\tadd\t%s\n", regnames[sp]);
972 }
973}
974
975/* generates the function exit code */
976/* Returns 1 if tail code was generated. */
977static int function_bottom(FILE * f, struct Var *v, long offset,int firsttail)
978{
979 int i;
980 int tail=0;
981
982 int regcount = 0;
983 for (i = FIRST_GPR + SCRATCH_GPRS + RESERVED_GPRS; i <= LAST_GPR - 3; ++i) {
984 if (regused[i] && !regscratch[i])
985 ++regcount;
986 }
987
988 if ((offset == 4) && optsize)
989 emit(f, "\tldinc\t%s\t// shortest way to add 4 to sp\n", regnames[sp]);
990 else if (offset) {
991 emit_constanttotemp(f, -offset); // Negative range extends one integer further than positive range.
992 emit(f, "\tsub\t%s\n", regnames[sp]);
993 }
994
995 if(optsize) // If we're optimising for size we can potentially save some bytes in the function tails.
996 {
997 if(regcount)
998 {
999 /* We have to restore some registers. Jump into the tail code at the appropriate place. */
1000 if(regcount<(5-SCRATCH_GPRS) || !firsttail)
1001 {
1002 emit(f,"\t.lipcrel\t.functiontail, %d\n",((5-SCRATCH_GPRS)-regcount)*2);
1003 emit(f,"\tadd\t%s\n\n",regnames[pc]);
1004 }
1005 if(firsttail)
1006 {
1007 /* This is the first time we've needed to restore registers - generate tail code */
1008 emit(f,".functiontail:\n");
1009 for (i = LAST_GPR - 3; i >= FIRST_GPR + SCRATCH_GPRS; --i) {
1010 if (!regscratch[i])
1011 emit(f, "\tldinc\t%s\n\tmr\t%s\n\n", regnames[sp], regnames[i]);
1012 }
1013 emit(f, "\tldinc\t%s\n\tmr\t%s\n\n", regnames[sp], regnames[pc]);
1014 if(f)
1015 tail=1; /* Higher optimisation levels do a dummy run with null file */
1016 }
1017 }
1018 else
1019 {
1020 /* Didn't need to preserve any registers, just restore PC */
1021 emit(f, "\tldinc\t%s\n\tmr\t%s\n\n", regnames[sp], regnames[pc]);
1022 }
1023 }
1024 else
1025 {
1026 for (i = LAST_GPR - 3; i >= FIRST_GPR + SCRATCH_GPRS; --i) {
1027 if (regused[i] && !regscratch[i])
1028 emit(f, "\tldinc\t%s\n\tmr\t%s\n\n", regnames[sp], regnames[i]);
1029 }
1030 emit(f, "\tldinc\t%s\n\tmr\t%s\n\n", regnames[sp], regnames[pc]);
1031 }
1032 return(tail);
1033}
1034
1035/****************************************/
1036/* End of private data and functions. */
1037/****************************************/
1038
1039/* Does necessary initializations for the code-generator. Gets called */
1040/* once at the beginning and should return 0 in case of problems. */
1041int init_cg(void)
1042{
1043 int i;
1044 /* Initialize some values which cannot be statically initialized */
1045 /* because they are stored in the target's arithmetic. */
1046 maxalign = l2zm(4L);
1047 char_bit = l2zm(8L);
1048 stackalign = l2zm(4);
1049
1050 flag_832_bigendian=0;
1051 if(g_flags[FLAG_BE]&USEDFLAG)
1052 flag_832_bigendian=1;
1053 else if(!g_flags[FLAG_BE]&USEDFLAG)
1054 printf("Neither -eb nor -el specified - defaulting to little-endian\n");
1055
1056#ifndef V09G
1057 clist_copy_stack=0;
1058 clist_copy_static=0;
1059 clist_copy_pointer=0;
1060#endif
1061
1062 // We have full load-store align, so in size mode we can pack data more tightly...
1063
1064 for (i = 0; i <= MAX_TYPE; i++) {
1065 sizetab[i] = l2zm(msizetab[i]);
1066 align[i] = optsize ? 1 : l2zm(malign[i]);
1067
1068// Can't align everything to 4 bytes for speed without messing up struct packing. Is there a better way?
1069// align[i] = optspeed ? 4 : (optsize ? 1 : l2zm(malign[i]));
1070// align[i] = l2zm(malign[i]);
1071 }
1072
1073 regnames[0] = "noreg";
1074 for (i = FIRST_GPR; i <= LAST_GPR - 1; i++) {
1075 regnames[i] = mymalloc(5);
1076 sprintf(regnames[i], "r%d", i - FIRST_GPR);
1077 regsize[i] = l2zm(4L);
1078 regtype[i] = &ltyp;
1079 regsa[i] = 0;
1080 }
1081 regnames[i] = mymalloc(5);
1082 sprintf(regnames[i], "tmp");
1083 regsize[i] = l2zm(4L);
1084 regtype[i] = &ltyp;
1085 regsa[i] = 1;
1086 for (i = FIRST_FPR; i <= LAST_FPR; i++) {
1087 regnames[i] = mymalloc(10);
1088 sprintf(regnames[i], "fpr%d", i - FIRST_FPR);
1089 regsize[i] = l2zm(8L);
1090 regtype[i] = &ldbl;
1091 }
1092
1093 /* Use multiple ccs. */
1094 multiple_ccs = 0;
1095
1096 /* Initialize the min/max-settings. Note that the types of the */
1097 /* host system may be different from the target system and you may */
1098 /* only use the smallest maximum values ANSI guarantees if you */
1099 /* want to be portable. */
1100 /* That's the reason for the subtraction in t_min[INT]. Long could */
1101 /* be unable to represent -2147483648 on the host system. */
1102 t_min[CHAR] = l2zm(-128L);
1103 t_min[SHORT] = l2zm(-32768L);
1104 t_min[INT] = zmsub(l2zm(-2147483647L), l2zm(1L));
1105 t_min[LONG] = t_min(INT);
1106 t_min[LLONG] = zmlshift(l2zm(1L), l2zm(63L));
1107 t_min[MAXINT] = t_min(LLONG);
1108 t_max[CHAR] = ul2zum(127L);
1109 t_max[SHORT] = ul2zum(32767UL);
1110 t_max[INT] = ul2zum(2147483647UL);
1111 t_max[LONG] = t_max(INT);
1112 t_max[LLONG] = zumrshift(zumkompl(ul2zum(0UL)), ul2zum(1UL));
1113 t_max[MAXINT] = t_max(LLONG);
1114 tu_max[CHAR] = ul2zum(255UL);
1115 tu_max[SHORT] = ul2zum(65535UL);
1116 tu_max[INT] = ul2zum(4294967295UL);
1117 tu_max[LONG] = t_max(UNSIGNED | INT);
1118 tu_max[LLONG] = zumkompl(ul2zum(0UL));
1119 tu_max[MAXINT] = t_max(UNSIGNED | LLONG);
1120
1121 /* Reserve a few registers for use by the code-generator. */
1122 /* This is not optimal but simple. */
1123 tmp = FIRST_GPR + 8;
1124 pc = FIRST_GPR + 7;
1125 sp = FIRST_GPR + 6;
1126 t1 = FIRST_GPR; // r0, also return register.
1127 t2 = FIRST_GPR + 1;
1128// f1=FIRST_FPR;
1129// f2=FIRST_FPR+1;
1130
1131 for (i = FIRST_GPR; i <= LAST_GPR; i++)
1132 regscratch[i] = 0;
1133 for (i = FIRST_FPR; i <= LAST_FPR; i++)
1134 regscratch[i] = 0;
1135
1136 regsa[FIRST_GPR] = 1; // Allocate the return register
1137 regsa[t1] = 1;
1138 regsa[t2] = 0;
1139 regsa[sp] = 1;
1140 regsa[pc] = 1;
1141 regsa[tmp] = 1;
1142 regscratch[FIRST_GPR] = 0;
1143 for(i=FIRST_GPR+RESERVED_GPRS;i<(FIRST_GPR+RESERVED_GPRS+SCRATCH_GPRS);++i)
1144 regscratch[i] = 1;
1145 regscratch[sp] = 0;
1146 regscratch[pc] = 0;
1147
1148 target_macros = marray;
1149
1150 return 1;
1151}
1152
1153void init_db(FILE * f)
1154{
1155}
1156
1157int freturn(struct Typ *t)
1158/* Returns the register in which variables of type t are returned. */
1159/* If the value cannot be returned in a register returns 0. */
1160/* A pointer MUST be returned in a register. The code-generator */
1161/* has to simulate a pseudo register if necessary. */
1162{
1163 if (ISFLOAT(t->flags))
1164 return 0;
1165 if (ISSTRUCT(t->flags) || ISUNION(t->flags))
1166 return 0;
1167 if (zmleq(szof(t), l2zm(4L)))
1168 return FIRST_GPR;
1169 else
1170 return 0;
1171}
1172
1173int reg_pair(int r, struct rpair *p)
1174/* Returns 0 if the register is no register pair. If r */
1175/* is a register pair non-zero will be returned and the */
1176/* structure pointed to p will be filled with the two */
1177/* elements. */
1178{
1179 return 0;
1180}
1181
1182/* estimate the cost-saving if object o from IC p is placed in
1183 register r */
1184int cost_savings(struct IC *p, int r, struct obj *o)
1185{
1186 int c = p->code;
1187 if(o->v && isextern(o->v->storage_class)) // Externs are particularly costly due to the ldinc r7 shuffle
1188 return(o->flags & DREFOBJ ? 5 : 3);
1189 if (o->flags & VKONST) {
1190 if (isextern(o->flags) || isstatic(o->flags))
1191 return 2;
1192 else {
1193 struct obj *o2 = &o->v->cobj;
1194 int c = count_constantchunks(o2->val.vmax);
1195 return c - 1;
1196 }
1197 }
1198 if (o->flags & DREFOBJ)
1199 return 2;
1200 if (c == SETRETURN)// && r == p->z.reg && !(o->flags & DREFOBJ))
1201 return 1;
1202 if (c == GETRETURN)// && r == p->q1.reg && !(o->flags & DREFOBJ))
1203 return 1;
1204 return 1;
1205}
1206
1207int regok(int r, int t, int mode)
1208/* Returns 0 if register r cannot store variables of */
1209/* type t. If t==POINTER and mode!=0 then it returns */
1210/* non-zero only if the register can store a pointer */
1211/* and dereference a pointer to mode. */
1212{
1213 if (r == 0)
1214 return 0;
1215 t &= NQ;
1216 if (ISFLOAT(t) && r >= FIRST_FPR && r <= LAST_FPR)
1217 return 1;
1218 if (t == POINTER && r >= FIRST_GPR && r <= LAST_GPR)
1219 return 1;
1220 if (t >= CHAR && t <= LONG && r >= FIRST_GPR && r <= LAST_GPR)
1221 return 1;
1222 return 0;
1223}
1224
1225int dangerous_IC(struct IC *p)
1226/* Returns zero if the IC p can be safely executed */
1227/* without danger of exceptions or similar things. */
1228/* vbcc may generate code in which non-dangerous ICs */
1229/* are sometimes executed although control-flow may */
1230/* never reach them (mainly when moving computations */
1231/* out of loops). */
1232/* Typical ICs that generate exceptions on some */
1233/* machines are: */
1234/* - accesses via pointers */
1235/* - division/modulo */
1236/* - overflow on signed integer/floats */
1237{
1238 int c = p->code;
1239 if ((p->q1.flags & DREFOBJ) || (p->q2.flags & DREFOBJ)
1240 || (p->z.flags & DREFOBJ))
1241 return 1;
1242 if ((c == DIV || c == MOD) && !isconst(q2))
1243 return 1;
1244 return 0;
1245}
1246
1247int must_convert(int o, int t, int const_expr)
1248/* Returns zero if code for converting np to type t */
1249/* can be omitted. */
1250/* On the PowerPC cpu pointers and 32bit */
1251/* integers have the same representation and can use */
1252/* the same registers. */
1253{
1254 int op = o & NQ, tp = t & NQ;
1255 if ((op == INT || op == LONG || op == POINTER)
1256 && (tp == INT || tp == LONG || tp == POINTER))
1257 return 0;
1258 if (op == DOUBLE && tp == LDOUBLE)
1259 return 0;
1260 if (op == LDOUBLE && tp == DOUBLE)
1261 return 0;
1262 return 1;
1263}
1264
1265void gen_ds(FILE * f, zmax size, struct Typ *t)
1266/* This function has to create <size> bytes of storage */
1267/* initialized with zero. */
1268{
1269 if (newobj && section != SPECIAL)
1270 emit(f, "%ld\n", zm2l(size));
1271 else
1272 emit(f, "\t.space\t%ld\n", zm2l(size));
1273 newobj = 0;
1274}
1275
1276
1277/* This function has to make sure the next data is
1278 aligned to multiples of <align> bytes.
1279 If the speed optimisation flag is set, always align
1280 to four bytes. */
1281void gen_align(FILE * f, zmax align)
1282{
1283 if(optspeed)
1284 emit(f,"\t.align\t4\n");
1285 else if (zm2l(align) > 1)
1286 emit(f, "\t.align\t%d\n", align);
1287}
1288
1289void gen_var_head(FILE * f, struct Var *v)
1290/* This function has to create the head of a variable */
1291/* definition, i.e. the label and information for */
1292/* linkage etc. */
1293{
1294 int constflag;
1295 char *sec;
1296 if (v->clist)
1297 constflag = is_const(v->vtyp);
1298 if (v->storage_class == STATIC) {
1299 if (ISFUNC(v->vtyp->flags))
1300 return;
1301 if (!special_section(f, v)) {
1302 if (v->clist && (!constflag)) { // || (g_flags[2] & USEDFLAG))
1303// && section != DATA) {
1304 emit(f, "%s.%x\n",dataname,sectionid);
1305 ++sectionid;
1306 if (f)
1307 section = DATA;
1308 }
1309 if (v->clist && constflag) { // && !(g_flags[2] & USEDFLAG)
1310// && section != RODATA) {
1311 emit(f, "%s.%x\n",rodataname,sectionid);
1312 ++sectionid;
1313 if (f)
1314 section = RODATA;
1315 }
1316 if (!v->clist) { // && section != BSS) {
1317 emit(f, "%s.%x\n",bssname,sectionid);
1318 ++sectionid;
1319 if (f)
1320 section = BSS;
1321 }
1322 }
1323 if (v->clist || section == SPECIAL) {
1324 gen_align(f, falign(v->vtyp));
1325 emit(f, "%s%ld:\n", labprefix, zm2l(v->offset));
1326 } else {
1327 gen_align(f, falign(v->vtyp));
1328 emit(f, "\t.lcomm\t%s%ld,", labprefix, zm2l(v->offset));
1329 }
1330 newobj = 1;
1331 }
1332 if (v->storage_class == EXTERN) {
1333// emit(f, "\t.global\t%s%s\n", idprefix, v->identifier);
1334 if (v->flags & (DEFINED | TENTATIVE)) {
1335 if (!special_section(f, v)) {
1336 if (v->clist && (!constflag)) { // || (g_flags[2] & USEDFLAG))
1337// && section != DATA) {
1338 emit(f, "%s.%x\n",dataname,sectionid);
1339 ++sectionid;
1340 if (f)
1341 section = DATA;
1342 }
1343 if (v->clist && constflag) { // && !(g_flags[2] & USEDFLAG)
1344// && section != RODATA) {
1345 emit(f, "%s.%x\n",rodataname,sectionid);
1346 ++sectionid;
1347 if (f)
1348 section = RODATA;
1349 }
1350 if (!v->clist) { // && section != BSS) {
1351 emit(f, "%s.%x\n",bssname,sectionid);
1352 ++sectionid;
1353 if (f)
1354 section = BSS;
1355 }
1356 }
1357 if (v->clist || section == SPECIAL) {
1358 gen_align(f, falign(v->vtyp));
1359 if (isweak(v))
1360 emit(f, "\t.weak\t%s%s\n", idprefix, v->identifier);
1361 else
1362 emit(f, "\t.global\t%s%s\n", idprefix, v->identifier);
1363 emit(f, "%s%s:\n", idprefix, v->identifier);
1364 } else {
1365 gen_align(f, falign(v->vtyp));
1366 if (isweak(v))
1367 emit(f, "\t.weak\t%s%s\n", idprefix, v->identifier);
1368 else {
1369 emit(f, "\t.global\t%s%s\n", idprefix, v->identifier);
1370 emit(f, "\t.comm\t%s%s,", idprefix, v->identifier);
1371 }
1372 }
1373 newobj = 1;
1374 }
1375 }
1376}
1377
1378void gen_dc(FILE * f, int t, struct const_list *p)
1379/* This function has to create static storage */
1380/* initialized with const-list p. */
1381{
1382 if (!p->tree) {
1383 switch (t & NQ) {
1384 case CHAR:
1385 emit(f, "\t.byte\t");
1386 break;
1387 case SHORT:
1388 emit(f, "\t.short\t");
1389 break;
1390 case LONG:
1391 case INT:
1392 case MAXINT:
1393 case POINTER:
1394 emit(f, "\t.int\t");
1395 break;
1396 case LLONG:
1397 emit(f, "//FIXME - unsupported type\n");
1398 emit(f, "\t.long\t");
1399// ierror(0);
1400 break;
1401 default:
1402 printf("gen_dc: unsupported type 0x%x\n", t);
1403 ierror(0);
1404 }
1405 emitval(f, &p->val, t & NU);
1406 emit(f, "\n");
1407
1408#if 0
1409 if (ISFLOAT(t)) {
1410 /* auch wieder nicht sehr schoen und IEEE noetig */
1411 unsigned char *ip;
1412 ip = (unsigned char *)&p->val.vdouble;
1413 emit(f, "0x%02x%02x%02x%02x", ip[0], ip[1], ip[2], ip[3]);
1414 if ((t & NQ) != FLOAT) {
1415 emit(f, ",0x%02x%02x%02x%02x", ip[4], ip[5], ip[6], ip[7]);
1416 }
1417 } else {
1418 emitval(f, &p->val, t & NU);
1419 }
1420#endif
1421 } else {
1422 struct obj *o = &p->tree->o;
1423 emit(f, "\t\t\t\t\t\t// Declaring from tree\n");
1424 if (isextern(o->v->storage_class)) {
1425 emit(f, "\t\t\t\t\t\t// extern (offset %d)\n", o->val.vmax);
1426 if (o->val.vmax)
1427 emit(f, "\t.ref\t_%s, %d\n", o->v->identifier, o->val.vmax);
1428 else
1429 emit(f, "\t.ref\t_%s\n", o->v->identifier);
1430 } else if (isstatic(o->v->storage_class)) {
1431 emit(f, "\t\t\t\t\t\t// static\n");
1432 if(o->val.vlong)
1433 emit(f, "\t.ref\t%s%d,%d\n", labprefix, zm2l(o->v->offset),o->val.vlong);
1434 else
1435 emit(f, "\t.ref\t%s%d\n", labprefix, zm2l(o->v->offset));
1436 } else {
1437 printf("error: GenDC (tree) - unknown storage class 0x%x!\n", o->v->storage_class);
1438 }
1439 }
1440 newobj = 0;
1441}
1442
1443
1444/* Return 1 if any of p's operands uses predec or postinc addressing mode */
1445int check_am(struct IC *p)
1446{
1447 if(p->q1.am && (p->q1.am->type==AM_POSTINC || p->q1.am->type==AM_PREDEC))
1448 return(1);
1449 if(p->q2.am && (p->q2.am->type==AM_POSTINC || p->q2.am->type==AM_PREDEC))
1450 return(1);
1451 if(p->z.am && (p->z.am->type==AM_POSTINC || p->z.am->type==AM_PREDEC))
1452 return(1);
1453 return(0);
1454}
1455
1456/* The main code-generation routine. */
1457/* f is the stream the code should be written to. */
1458/* p is a pointer to a doubly linked list of ICs */
1459/* containing the function body to generate code for. */
1460/* v is a pointer to the function. */
1461/* offset is the size of the stackframe the function */
1462/* needs for local variables. */
1463
1464void gen_code(FILE * f, struct IC *p, struct Var *v, zmax offset)
1465/* The main code-generation. */
1466{
1467 static int idemp = 0;
1468 static int firsttail=1;
1469 int reversecmp=0;
1470 int c, t, i;
1471 struct IC *m;
1472 argsize = 0;
1473 // if(DEBUG&1)
1474
1475 if(!p)
1476 printf("(gen_code called with null IC list?)\n");
1477
1478 for (c = 1; c <= MAXR; c++)
1479 regs[c] = regsa[c];
1480 pushed = 0;
1481 notyetpopped = 0;
1482
1483#if 0
1484 if (!idemp) {
1485 sectionid = 0;
1486 if (p && p->file) {
1487 int v;
1488 char *c = p->file;
1489 idemp = 1;
1490 while (v = *c++) {
1491 sectionid <<= 3;
1492 sectionid ^= v;
1493 }
1494 printf("Created section ID %x\n",sectionid);
1495 }
1496 else
1497 printf("No sectionid created (%x, %x)\n",p,p ? p->file : 0);
1498 }
1499#endif
1500
1501 for (m = p; m; m = m->next) {
1502 c = m->code;
1503 t = m->typf & NU;
1504 if (c == ALLOCREG) {
1505 regs[m->q1.reg] = 1;
1506 continue;
1507 }
1508 if (c == FREEREG) {
1509 regs[m->q1.reg] = 0;
1510 continue;
1511 }
1512
1513 /* convert MULT/DIV/MOD with powers of two */
1514 // Perversely, mul is faster than shifting on 832, so we only want to do this for div.
1515 // FIXME - we can do this for signed values too.
1516 if ((t & NQ) <= LONG && (m->q2.flags & (KONST | DREFOBJ)) == KONST && (t & NQ) <= LONG
1517 && (((c == DIV || c == MOD) && (t & UNSIGNED)))) {
1518 eval_const(&m->q2.val, t);
1519 i = pof2(vmax);
1520 if (i) {
1521 if (c == MOD) {
1522 vmax = zmsub(vmax, l2zm(1L));
1523 m->code = AND;
1524 } else {
1525 vmax = l2zm(i - 1);
1526 if (c == DIV)
1527 m->code = RSHIFT;
1528 else
1529 m->code = LSHIFT;
1530 }
1531 c = m->code;
1532 gval.vmax = vmax;
1533 eval_const(&gval, MAXINT);
1534 if (c == AND) { // FIXME - why?
1535 insert_const(&m->q2.val, t);
1536 } else {
1537 insert_const(&m->q2.val, INT);
1538 p->typf2 = INT;
1539 }
1540 }
1541 }
1542 }
1543
1544 for (c = 1; c <= MAXR; c++) {
1545 if (regsa[c] || regused[c]) {
1546 BSET(regs_modified, c);
1547 }
1548 }
1549 localsize = (zm2l(offset) + 3) / 4 * 4;
1550
1551// printf("\nSeeking addressing modes for function %s\n",v->identifier);
1552 find_addressingmodes(p);
1553
1554 function_top(f, v, localsize);
1555// printf("%s:\n",v->identifier);
1556
1557 for (; p; p = p->next) {
1558// printic(stdout,p);
1559 c = p->code;
1560 t = q1typ(p);
1561
1562 if (c == NOP) {
1563 p->z.flags = 0;
1564 continue;
1565 }
1566 if (c == ALLOCREG) {
1567 if(DBGMSG)
1568 emit(f, "\t\t\t\t\t\t// allocreg %s\n", regnames[p->q1.reg]);
1569 regs[p->q1.reg] = 1;
1570 continue;
1571 }
1572 if (c == FREEREG) {
1573 if(DBGMSG)
1574 emit(f, "\t\t\t\t\t\t// freereg %s\n", regnames[p->q1.reg]);
1575 regs[p->q1.reg] = 0;
1576 continue;
1577 }
1578 if (c == LABEL) {
1579 int i;
1580 emit(f, "%s%d: # \n", labprefix, t);
1581 cleartempobj(f,tmp); // Can't carry temporary context past a label
1582 cleartempobj(f,t1);
1583 continue;
1584 }
1585
1586 if (DBGMSG && p->file)
1587 emit(f, "\n\t\t\t\t\t\t//%s, line %d\n", p->file, p->line);
1588 if(p->q1.am && p->q1.am->disposable)
1589 emit(f, "\t\t\t\t\t\t// Q1 disposable\n");
1590 if(p->q2.am && p->q2.am->disposable)
1591 emit(f, "\t\t\t\t\t\t// Q2 disposable\n");
1592 if(p->z.am && p->z.am->disposable)
1593 emit(f, "\t\t\t\t\t\t// Z disposable\n");
1594
1595 // OK
1596 if (c == BRA) {
1597 if(0) // FIXME - could duplicate function tail here. Perhaps do it depending on number of saved registers?
1598 function_bottom(f, v, localsize, 0);
1599 else
1600 emit_pcreltotemp(f, labprefix, t);
1601 emit(f, "\tadd\t%s\n", regnames[pc]);
1602 continue;
1603 }
1604 // OK
1605 if (c >= BEQ && c < BRA) {
1606 if(reversecmp)
1607 {
1608 switch(c)
1609 {
1610 case BLT:
1611 c=BGT;
1612 break;
1613 case BLE:
1614 c=BGE;
1615 break;
1616 case BGT:
1617 c=BLT;
1618 break;
1619 case BGE:
1620 c=BLE;
1621 break;
1622 }
1623 }
1624 emit(f, "\tcond\t%s\n",ccs[c - BEQ]);
1625 if(DBGMSG)
1626 emit(f, "\t\t\t\t\t\t//conditional branch %s\n",reversecmp ? "reversed" : "regular");
1627 reversecmp=0;
1628 emit_pcreltotemp(f, labprefix, t); // FIXME - double-check that we shouldn't include an offset here.
1629 emit(f, "\t\tadd\tr7\n");
1630 continue;
1631 }
1632 // Investigate - but not currently seeing it used.
1633 if (c == MOVETOREG) {
1634 emit(f, "\t\t\t\t\t\t//CHECKME movetoreg\n");
1635 emit_objtoreg(f, &p->q1, ztyp(p),zreg);
1636 continue;
1637 }
1638 // Investigate - but not currently seeing it used.
1639 if (c == MOVEFROMREG) {
1640 emit(f, "\t\t\t\t\t\t//CHECKME movefromreg\n");
1641 store_reg(f, p->q1.reg, &p->z, regtype[p->q1.reg]->flags);
1642 continue;
1643 }
1644 // Reject types we can't handle - anything beyond a pointer and chars with more than 1 byte.
1645// if ((c == PUSH)
1646// && ((t & NQ) > POINTER || ((t & NQ) == CHAR && zm2l(p->q2.val.vmax) != 1))) {
1647// printf("Pushing a type we don't yet handle: 0x%x\n", t);
1648// ierror(0);
1649// }
1650
1651 if ((c == ASSIGN) && ((t & NQ) > UNION)) {
1652 printf("Assignment of a type we don't yet handle: 0x%x\n", t);
1653 ierror(0);
1654 }
1655
1656 // Avoid stack top slot trickery if the operation involves pushing operands to the stack
1657 if(c==DIV || c==MOD ||
1658 ((c==ASSIGN || c==PUSH) && ((t & NQ) > POINTER || ((t & NQ) == CHAR && zm2l(p->q2.val.vmax) != 1))))
1659 p = preload(f, p, 0); // Setup zreg, etc.
1660 else
1661 p = preload(f, p, 1); // Setup zreg, etc.
1662
1663 c = p->code;
1664
1665 if (c == SUBPFP)
1666 c = SUB;
1667 if (c == ADDI2P)
1668 c = ADD;
1669 if (c == SUBIFP)
1670 c = SUB;
1671
1672// emit(f, "// code 0x%x, q1->v: %x\n", c,&p->q1.v);
1673// if(p->prev && matchobj(f,&p->q1,&p->prev->q1))
1674// emit(f, "// Matching objs found\n", p->prev->code,&p->prev->q1.v);
1675
1676 if (c == CONVERT) {
1677 if(DBGMSG)
1678 emit(f, "\t\t\t\t\t\t//FIXME convert\n");
1679 if (ISFLOAT(q1typ(p)) || ISFLOAT(ztyp(p))) {
1680 printf("Float not yet supported\n");
1681 ierror(0);
1682 }
1683 if (sizetab[q1typ(p) & NQ] < sizetab[ztyp(p) & NQ]) {
1684 int shamt = 0;
1685 if(DBGMSG)
1686 emit(f,"\t\t\t\t\t\t//Converting to wider type...\n");
1687 switch (q1typ(p) & NU) {
1688 case CHAR | UNSIGNED:
1689 case SHORT | UNSIGNED:
1690 if(DBGMSG)
1691 emit(f,"\t\t\t\t\t\t//But unsigned, so no need to extend\n");
1692
1693 if(involvesreg(z)) {
1694 emit_prepobj(f, &p->z, ztyp(p), zreg, 0);
1695 emit_objtoreg(f, &p->q1, q1typ(p), tmp);
1696 save_temp(f, p, zreg);
1697 // WARNING - might need to invalidate temp objects here...
1698 } else {
1699 emit_objtoreg(f, &p->q1, q1typ(p), zreg);
1700 save_result(f, p);
1701 // WARNING - might need to invalidate temp objects here...
1702 }
1703 break;
1704 case CHAR:
1705 emit_objtoreg(f, &p->q1, q1typ(p), zreg);
1706 emit_constanttotemp(f,0xffffff80);
1707 emit(f,"\tadd\t%s\n",regnames[zreg]);
1708 emit(f,"\txor\t%s\n",regnames[zreg]);
1709 cleartempobj(f,zreg);
1710 save_result(f, p);
1711 break;
1712 case SHORT:
1713 emit_objtoreg(f, &p->q1, q1typ(p), zreg);
1714 emit_constanttotemp(f,0xffff8000);
1715 emit(f,"\tadd\t%s\n",regnames[zreg]);
1716 emit(f,"\txor\t%s\n",regnames[zreg]);
1717 cleartempobj(f,zreg);
1718 save_result(f, p);
1719 break;
1720 }
1721// settempobj(f,zreg,&p->z,0,0);
1722 } else if(sizetab[q1typ(p) & NQ] >= sizetab[ztyp(p) & NQ]) { // Reducing the size, must mask off excess bits...
1723 if(DBGMSG)
1724 emit(f,"\t\t\t\t\t\t// (convert - reducing type %x to %x\n",q1typ(p),ztyp(p));
1725
1726 // If Z is not a register then we're storing a halfword or byte, and thus don't need to mask...
1727
1728 if(((p->q1.flags&(REG|DREFOBJ))==REG) && (p->z.flags&(REG|DREFOBJ))!=REG) {
1729 if(p->z.flags&DREFOBJ) { // Can't use stmpdec for dereferenced objects
1730 emit_prepobj(f, &p->z, t, zreg, 0); // Need an offset
1731 emit_objtoreg(f, &p->q1, q1typ(p), tmp);
1732 save_temp(f,p,zreg);
1733#if 0
1734 emit_prepobj(f, &p->z, t, tmp, 0); // Need an offset
1735 emit(f, "\texg\t%s\n", regnames[q1reg]);
1736// if(!isstackparam(&p->z) || (p->z.flags&DREFOBJ))
1737 emit_sizemod(f,ztyp(p));
1738 emit(f, "\tst\t%s\n", regnames[q1reg]);
1739 if(p->z.am && p->z.am->disposable && p->q1.am && p->q1.am->disposable)
1740 emit(f, "\t\t\t\t\t\t// Both q1 and z are disposable, not bothering to undo exg\n");
1741 else
1742 emit(f, "\texg\t%s\n", regnames[q1reg]);
1743#endif
1744 }
1745 else {
1746 // Use stmpdec if q1 is already in a register...
1747 emit_prepobj(f, &p->z, ztyp(p), tmp, 4); // Need an offset
1748 if(!isstackparam(&p->z))
1749 emit_sizemod(f,ztyp(p));
1750 emit(f,"\tstmpdec\t%s\n",regnames[q1reg]);
1751 }
1752 }
1753 else { // Destination is a register - we must mask...
1754 // Potential optimisation here - track which ops could have caused a value to require truncation.
1755 // Also figure out what's happening next to the value. If it's only being added, anded, ored, xored
1756 // and then truncated by a write to memory we don't need to worry.
1757 if(!isreg(q1) || !isreg(z) || q1reg!=zreg) // Do we just need to mask in place, or move the value first?
1758 {
1759 if(!isreg(z))
1760 zreg=t1;
1761 emit_prepobj(f, &p->z, ztyp(p), t1, 0);
1762
1763 emit_objtoreg(f, &p->q1, t,tmp);
1764 emit(f,"\t\t\t\t\t\t//Saving to reg %s\n",regnames[zreg]);
1765 save_temp(f, p, zreg);
1766 }
1767// else
1768 if(zreg!=sp && (p->z.flags&(DREFOBJ|REG))==REG)
1769 {
1770 switch(ztyp(p)&NQ) {
1771 case SHORT:
1772 emit_constanttotemp(f, 0xffff);
1773 emit(f, "\tand\t%s\n", regnames[zreg]);
1774 break;
1775 case CHAR:
1776 emit_constanttotemp(f, 0xff);
1777 emit(f, "\tand\t%s\n", regnames[zreg]);
1778 break;
1779 default:
1780 emit(f,"\t\t\t\t\t\t//No need to mask - same size\n");
1781 break;
1782 }
1783 }
1784 }
1785 }
1786 continue;
1787 }
1788
1789 if (c == KOMPLEMENT) {
1790 if(DBGMSG)
1791 emit(f, "\t\t\t\t\t\t//comp\n");
1792 emit_objtoreg(f, &p->q1, q1typ(p), zreg);
1793 emit_constanttotemp(f,-1);
1794 emit(f, "\txor\t%s\n", regnames[zreg]);
1795// cleartempobj(f,zreg);
1796 save_result(f, p);
1797 continue;
1798 }
1799 // May not need to actually load the register here - certainly check before emitting code.
1800 if (c == SETRETURN) {
1801 if(DBGMSG)
1802 emit(f, "\t\t\t\t\t\t//setreturn\n");
1803 emit_objtoreg(f, &p->q1, q1typ(p), zreg);
1804 BSET(regs_modified, p->z.reg);
1805 continue;
1806 }
1807 // Investigate - May not be needed for register mode?
1808 if (c == GETRETURN) {
1809 if(DBGMSG)
1810 emit(f, "\t\t\t\t\t\t// (getreturn)");
1811 if (p->q1.reg) {
1812 zreg = p->q1.reg;
1813 save_result(f, p);
1814 } else {
1815 if(DBGMSG)
1816 emit(f, " not reg\n");
1817 p->z.flags = 0;
1818 }
1819 continue;
1820 }
1821 // OK - figure out what the bvunite stuff is all about.
1822 if (c == CALL) {
1823 int reg;
1824 if(DBGMSG)
1825 emit(f, "\t\t\t\t\t\t//call\n");
1826 if ((p->q1.flags & (VAR | DREFOBJ)) == VAR && p->q1.v->fi && p->q1.v->fi->inline_asm) {
1827 emit_inline_asm(f, p->q1.v->fi->inline_asm);
1828 cleartempobj(f,t1);
1829 cleartempobj(f,tmp);
1830 /* FIXME - restore stack from pushed arguments? */
1831 } else {
1832 /* FIXME - deal with different object types here */
1833 if (p->q1.v->storage_class == STATIC) {
1834 // FIXME - double-check that we shouldn't include an offset here.
1835 emit_pcreltotemp2(f, &p->q1);
1836 if (p->q1.flags & DREFOBJ) {
1837 emit(f, "\taddt\t%s\t//Deref function pointer\n", regnames[pc]);
1838 emit(f, "\tldt\n\texg\t%s\n", regnames[pc]);
1839 } else
1840 emit(f, "\tadd\t%s\n", regnames[pc]);
1841 } else if (p->q1.v->storage_class == EXTERN) {
1842 if (p->q1.flags & DREFOBJ) { // Is this a function pointer?
1843 emit_externtotemp(f, p->q1.v->identifier, p->q1.val.vmax);
1844 emit(f, "\tldt\t// deref function ptr\n");
1845 emit(f, "\texg\t%s\n", regnames[pc]);
1846 }
1847 else {
1848 emit_pcreltotemp2(f, &p->q1);
1849 emit(f, "\tadd\t%s\n", regnames[pc]);
1850 }
1851 } else {
1852 emit_objtoreg(f, &p->q1, t, tmp);
1853 emit(f, "\texg\t%s\n", regnames[pc]);
1854 }
1855
1856 cleartempobj(f,tmp);
1857
1858 /* If we have an addressingmode, see if we're able to defer stack popping. */
1859 if(p->z.am)
1860 {
1861 switch(p->z.am->deferredpop)
1862 {
1863 /* If we couldn't defer popping due to flow control changes, we need to pop any previously
1864 deferred stack entries at this point.*/
1865 case DEFERREDPOP_FLOWCONTROL:
1866 emit(f,"\t\t\t\t\t\t// Flow control - popping %d + %d bytes\n",pushedargsize(p),notyetpopped);
1867 if(pushedargsize(p)+notyetpopped)
1868 {
1869 emit_constanttotemp(f, pushedargsize(p)+notyetpopped);
1870 emit(f, "\tadd\t%s\n", regnames[sp]);
1871 }
1872 pushed -= pushedargsize(p);
1873 notyetpopped=0;
1874 break;
1875
1876 /* If we couldn't defer popping due to nested calls then we only pop this function's stack entries. */
1877 case DEFERREDPOP_NESTEDCALLS:
1878 emit(f,"\t\t\t\t\t\t// Nested call - popping %d bytes\n",pushedargsize(p));
1879 if(pushedargsize(p))
1880 {
1881 emit_constanttotemp(f, pushedargsize(p));
1882 emit(f, "\tadd\t%s\n", regnames[sp]);
1883 }
1884 pushed -= pushedargsize(p);
1885 break;
1886
1887 /* Otherwise, we're OK to defer popping until later. */
1888 case DEFERREDPOP_OK:
1889 notyetpopped+=pushedargsize(p);
1890 pushed -= pushedargsize(p);
1891 emit(f,"\t\t\t\t\t\t// Deferred popping of %d bytes (%d in total)\n",pushedargsize(p),notyetpopped);
1892 break;
1893 }
1894 }
1895 else if(pushedargsize(p))
1896 {
1897 emit_constanttotemp(f, pushedargsize(p));
1898 pushed -= pushedargsize(p);
1899 emit(f, "\tadd\t%s\n", regnames[sp]);
1900 }
1901// cleartempobj(f,tmp);
1902 cleartempobj(f,t1);
1903 }
1904 /*FIXME*/
1905 if ((p->q1.flags & (VAR | DREFOBJ)) == VAR && p->q1.v->fi
1906 && (p->q1.v->fi->flags & ALL_REGS)) {
1907 bvunite(regs_modified, p->q1.v->fi->regs_modified, RSIZE);
1908 } else {
1909 int i;
1910 for (i = 1; i <= MAXR; i++) {
1911 if (regscratch[i])
1912 BSET(regs_modified, i);
1913 }
1914 }
1915 continue;
1916 }
1917
1918 if ((c == ASSIGN || c == PUSH) && t == 0) {
1919 printf("Bad type for assign / push\n");
1920 ierror(0);
1921 }
1922 // Basically OK.
1923 if (c == PUSH) {
1924 int matchreg;
1925 if(DBGMSG)
1926 emit(f, "\t\t\t\t\t\t// (a/p push)\n");
1927
1928 /* Handle composite types */
1929 if((t & NQ) > POINTER || ((t & NQ) == CHAR && zm2l(p->q2.val.vmax) != 1)) {
1930// if(DBGMSG)
1931 emit(f,"\t\t\t\t\t\t// Pushing composite type - size %d, pushed size %d\n",opsize(p),pushsize(p));
1932 emit_inlinepush(f,p,t);
1933 pushed += pushsize(p);
1934 }
1935 else
1936 {
1937 /* need to take dt into account */
1938 if(DBGMSG)
1939 emit(f, "\t\t\t\t\t\t// a: pushed %ld, regnames[sp] %s\n", pushed, regnames[sp]);
1940 switch(t&NQ)
1941 {
1942 case INT:
1943 case LONG:
1944 case POINTER:
1945 emit_objtoreg(f, &p->q1, t, tmp);
1946 emit(f, "\tstdec\t%s\n", regnames[sp]);
1947 break;
1948 default:
1949 printf("Pushing unhandled type 0x%x to the stack\n",t);
1950 ierror(0);
1951 break;
1952 }
1953 pushed += pushsize(p);
1954 }
1955 continue;
1956 }
1957
1958 if (c == ASSIGN) {
1959 if(DBGMSG)
1960 emit(f, "\t\t\t\t\t\t// (a/p assign)\n");
1961 if (((t & NQ) == STRUCT) || ((t & NQ) == UNION) || ((t & NQ) == ARRAY)
1962 || ((t & NQ) == CHAR && opsize(p) != 1)) {
1963 emit_inlinememcpy(f,p,t);
1964 } else {
1965 // Is the small speedup here worth the complexity? (Yes, because it improves code density)
1966 // Use stmpdec if q1 is already in a register and we're not using addressing modes...
1967 if(!check_am(p) && ((p->q1.flags&(REG|DREFOBJ))==REG) && !(p->z.flags&REG))
1968 {
1969 if(p->z.flags&DREFOBJ) // Can't use stmpdec for dereferenced objects
1970 {
1971 emit_prepobj(f, &p->z, t, tmp, 0);
1972 emit(f, "\texg\t%s\n", regnames[q1reg]);
1973 emit_sizemod(f,t);
1974 emit(f, "\tst\t%s\n", regnames[q1reg]);
1975 if(p->z.am && p->z.am->disposable)
1976 {
1977 cleartempobj(f,tmp);
1978 emit(f, "\t\t\t\t\t\t// Object is disposable, not bothering to undo exg\n");
1979 }
1980 else
1981 emit(f, "\texg\t%s\n", regnames[q1reg]);
1982 }
1983 else
1984 {
1985 emit_prepobj(f, &p->z, t, tmp, 4); // Need an offset
1986 if(!isstackparam(&p->z))
1987 emit_sizemod(f,t);
1988 emit(f,"\tstmpdec\t%s\n",regnames[q1reg]);
1989 cleartempobj(f,tmp);
1990 }
1991 }
1992 else
1993 {
1994 emit_prepobj(f, &p->z, t, t1, 0);
1995 emit_objtoreg(f, &p->q1, t, tmp);
1996 save_temp(f, p, t1);
1997 }
1998 }
1999 continue;
2000 }
2001 // Seems to work.
2002 if (c == ADDRESS) {
2003 if(DBGMSG)
2004 emit(f, "\t\t\t\t\t\t// (address)\n");
2005 if(involvesreg(z))
2006 {
2007 emit_prepobj(f, &p->q1, POINTER, tmp, 0);
2008 save_temp(f,p,zreg);
2009 }
2010 else
2011 {
2012 emit_prepobj(f, &p->q1, POINTER, zreg, 0);
2013 save_result(f, p);
2014 }
2015 continue;
2016 }
2017 // OK
2018 if (c == MINUS) {
2019 if(DBGMSG)
2020 emit(f, "\t\t\t\t\t\t// (minus)\n");
2021 emit_objtoreg(f, &p->q1, q1typ(p), zreg);
2022 emit_constanttotemp(f,0);
2023 emit(f, "\texg %s\n\tsub %s\n", regnames[zreg], regnames[zreg]);
2024 settempobj(f,tmp,&p->q1,0,0); // Temp contains un-negated value
2025 // cleartempobj(f,tmp);
2026 save_result(f, p);
2027 continue;
2028 }
2029 // Compare - #
2030 // Revisit
2031 if (c == TEST) {
2032 if(DBGMSG)
2033 emit(f, "\t\t\t\t\t\t// (test)\n");
2034 if(!emit_objtoreg(f, &p->q1, t, tmp)) /* emit_objtoreg might already have set the Z flag */
2035 {
2036 emit(f,"\t\t\t\t// flags %x\n",p->q1.flags);
2037 if ((p->q1.flags & (REG|DREFOBJ)) == REG) // Can avoid mr if the value came from a register
2038 emit(f, "\tand\t%s\n", regnames[p->q1.reg]);
2039 else
2040 {
2041 emit(f, "\tmr\t%s\n\tand\t%s\n", regnames[t1], regnames[t1]);
2042 settempobj(f,t1,&p->q1,0,0);
2043 }
2044// cleartempobj(f,tmp);
2045// cleartempobj(f,t1);
2046 }
2047 continue;
2048 }
2049 // Compare
2050 // Revisit
2051 if (c == COMPARE) {
2052 if(DBGMSG)
2053 {
2054 emit(f, "\t\t\t\t\t\t// (compare)");
2055 if (q1typ(p) & UNSIGNED)
2056 emit(f, " (q1 unsigned)");
2057 else
2058 emit(f, " (q1 signed)");
2059 if (q2typ(p) & UNSIGNED)
2060 emit(f, " (q2 unsigned)");
2061 else
2062 emit(f, " (q2 signed)");
2063 emit(f,"\n");
2064 }
2065
2066 // If q2 is a register but q1 isn't we could reverse the comparison, but would then have to reverse
2067 // the subsequent conditional branch.
2068 // FIXME - can also reverse if one value is cached
2069
2070 if (!isreg(q1)) {
2071 if(isreg(q2)) { // Reverse the test.
2072 emit_objtoreg(f, &p->q1, t,tmp);
2073 q1reg=q2reg;
2074 reversecmp=1;
2075 } else { // Neither object is in a register, so load q1 into t1 and q2 into tmp.
2076 emit_objtoreg(f, &p->q1, t,t1);
2077 cleartempobj(f,t1);
2078 q1reg = t1;
2079 emit_objtoreg(f, &p->q2, t,tmp);
2080 }
2081 }
2082 else
2083 emit_objtoreg(f, &p->q2, t,tmp);
2084 if ((!(q1typ(p) & UNSIGNED)) && (!(q2typ(p) & UNSIGNED))) { // If we have a mismatch of signedness we treat as unsigned.
2085 int nextop=p->next->code; // Does the sign matter for the branch being done?
2086 if(nextop==FREEREG)
2087 nextop=p->next->next->code;
2088 if((nextop!=BEQ) && (nextop!=BNE))
2089 emit(f, "\tsgn\n"); // Signed comparison
2090 }
2091 emit(f, "\tcmp\t%s\n", regnames[q1reg]);
2092 continue;
2093 }
2094
2095 // Division and modulo
2096 if ((c == MOD) || (c == DIV)) {
2097 int targetreg=zreg;
2098 int doneq2=0;
2099 // FIXME - do we need to use switch_IC here?
2100 if(DBGMSG)
2101 emit(f, "\t\t\t\t\t\t//Call division routine\n");
2102
2103 // determine here whether R1 and R2 really need saving - may not be in use, or may be the target register.
2104 if(regs[t2] && zreg!=t2)
2105 {
2106 emit(f, "\tmt\t%s\n\tstdec\t%s\n", regnames[t2], regnames[sp]);
2107 cleartempobj(f,tmp);
2108 pushed+=4;
2109 }
2110 if(regs[t2+1] && zreg!=(t2+1))
2111 {
2112 emit(f, "\tmt\t%s\n\tstdec\t%s\n", regnames[t2 + 1], regnames[sp]);
2113 cleartempobj(f,tmp);
2114 pushed += 4;
2115 }
2116 // q1 must be written to t2, q2 must be written to t2+2
2117 // if q2 starts in t2 we have to avoid overwriting it.
2118
2119 // If q1 is already in t2, q2 can't be, so we don't need to worry about swapping
2120 if(!isreg(q1) || q1reg!=t2)
2121 {
2122 emit_objtoreg(f, &p->q1, t,tmp);
2123
2124 // Need to make sure we're not about to overwrite the other operand!
2125 if(isreg(q2) && q2reg==t2)
2126 {
2127 emit(f,"\texg\t%s\n",regnames[t2]);
2128 emit(f,"\tmr\t%s\n",regnames[t2+1]);
2129 doneq2=1;
2130 }
2131 else
2132 emit(f, "\tmr\t%s\n", regnames[t2]);
2133 }
2134 if(!doneq2 && (!isreg(q2) || q2reg!=t2+1))
2135 {
2136 emit_objtoreg(f, &p->q2, t,tmp);
2137 emit(f, "\tmr\t%s\n", regnames[t2 + 1]);
2138 }
2139 cleartempobj(f,t1);
2140 cleartempobj(f,t2);
2141
2142 if ((!(q1typ(p) & UNSIGNED)) && (!(q2typ(p) & UNSIGNED))) // If we have a mismatch of signedness we treat as unsigned.
2143 emit(f, "\t.lipcrel\t_div_s32bys32\n");
2144 else
2145 emit(f, "\t.lipcrel\t_div_u32byu32\n");
2146 emit(f, "\tadd\t%s\n", regnames[pc]);
2147
2148 // If the next IC is SetReturn from the same register we can skip saving the result.
2149 if(next_setreturn(p,zreg))
2150 {
2151 emit(f,"\t\t\t\t\t\t// Skipping save_result...\n");
2152 targetreg=t1;
2153 }
2154
2155 if (c == MOD)
2156 {
2157 if(targetreg!=t2)
2158 emit(f, "\tmt\t%s\n\tmr\t%s\n", regnames[t2], regnames[zreg]);
2159 }
2160 else
2161 {
2162 if(targetreg!=t1)
2163 emit(f, "\tmt\t%s\n\tmr\t%s\n", regnames[t1], regnames[zreg]);
2164 }
2165
2166 if(regs[t2+1] && zreg!=(t2+1))
2167 {
2168 emit(f, "\tldinc\t%s\n\tmr\t%s\n", regnames[sp], regnames[t2+1]);
2169 pushed -= 4;
2170 }
2171 if(regs[t2] && zreg!=t2)
2172 {
2173 emit(f, "\tldinc\t%s\n\tmr\t%s\n", regnames[sp], regnames[t2]);
2174 pushed -= 4;
2175 }
2176
2177 cleartempobj(f,tmp);
2178 cleartempobj(f,t1);
2179
2180 // Target not guaranteed to be a register.
2181 save_result(f, p);
2182
2183 continue;
2184 }
2185
2186 // Remaining arithmetic and bitwise operations
2187
2188 if ((c >= OR && c <= AND) || (c >= LSHIFT && c <= MULT)) {
2189 if(DBGMSG)
2190 emit(f, "\t\t\t\t\t\t// (bitwise/arithmetic) ");
2191 if(DBGMSG)
2192 emit(f, "\t//ops: %d, %d, %d\n", q1reg, q2reg, zreg);
2193 if(p->q1.am && p->q1.am->type==AM_ADDT)
2194 {
2195 if(DBGMSG)
2196 emit(f,"\t\t\t\t\t\t//Special case - addt\n");
2197 // FIXME - if q2 is already in tmp could reverse this
2198 if(p->q2.flags&KONST)
2199 {
2200 zreg=t1;
2201 emit_prepobj(f, &p->z, t, t1, 0);
2202
2203 emit_objtoreg(f, &p->q2, t,tmp);
2204 emit(f,"\taddt\t%s\n",regnames[p->q1.reg]);
2205 settempobj(f,tmp,&p->z,0,0);
2206 save_temp(f, p, zreg);
2207 obsoletetempobj(f,t1,&p->z,0);
2208// emit(f,"\tmr\t%s\n",regnames[p->z.reg]);
2209 }
2210 else
2211 {
2212 zreg=t1;
2213 emit_prepobj(f, &p->z, t, t1, 0);
2214
2215 emit_objtoreg(f, &p->q1, t,tmp);
2216 emit(f,"\taddt\t%s\n",regnames[p->q2.reg]);
2217 settempobj(f,tmp,&p->z,0,0);
2218 save_temp(f, p, zreg);
2219 obsoletetempobj(f,t1,&p->z,0);
2220// emit(f,"\tmr\t%s\n",regnames[p->z.reg]);
2221 }
2222 continue;
2223 }
2224
2225 if (involvesreg(q2) && q2reg == zreg) {
2226// printf("Target register and q2 are the same! Attempting a switch...\n");
2227 if (switch_IC(p)) {
2228 preload(f,p,1); // refresh q1reg, etc after switching the IC
2229 } else {
2230 emit(f,
2231 "\t\t\t\t\t\t// WARNING - evading q2 and target collision - check code for correctness.\n");
2232 zreg = t1;
2233 }
2234 }
2235 if (involvesreg(q1) && q1reg == zreg)
2236 emit(f,"\t\t\t\t\t\t// WARNING - q1 and target collision - check code for correctness.\n");
2237
2238 if (!isreg(q1) || q1reg != zreg) {
2239 emit_objtoreg(f, &p->q1, t,zreg);
2240// emit(f, "\tmr\t%s\n", regnames[zreg]); // FIXME - what happens if zreg and q1/2 are the same?
2241 }
2242 emit_objtoreg(f, &p->q2, t,tmp);
2243 if (c >= OR && c <= AND)
2244 emit(f, "\t%s\t%s\n", logicals[c - OR], regnames[zreg]);
2245 else {
2246 if (c == RSHIFT || c==MULT) // Modify right shift operations with appropriate signedness...
2247 {
2248// printf("q1typ: %x, q2typ: %x, ztyp: %x\n",q1typ(p),q2typ(p),ztyp(p));
2249 if (!(t & UNSIGNED))
2250 {
2251 // Evaluate q1 - if we're dealing with a constant that doesn't have bit 31 set we don't need sgn...
2252 if((!(p->typf2 & UNSIGNED) && c==RSHIFT)
2253 || (p->q1.flags&(KONST|DREFOBJ)!=KONST)
2254 || (val2zmax(&p->q1,p->typf)&0x80000000))
2255 emit(f, "\tsgn\n");
2256 }
2257 }
2258 emit(f, "\t%s\t%s\n", arithmetics[c - LSHIFT], regnames[zreg]);
2259 if(c==MULT)
2260 cleartempobj(f,tmp);
2261 }
2262 settempobj(f,zreg,&p->z,0,0);
2263 cleartempobj(f,zreg);
2264 save_result(f, p);
2265 continue;
2266 }
2267 printf("Unhandled IC\n");
2268 pric2(stdout, p);
2269 ierror(0);
2270 }
2271 if(function_bottom(f, v, localsize+notyetpopped,firsttail))
2272 firsttail=0;
2273}
2274
2275int shortcut(int code, int typ)
2276{
2277 // Only RSHIFT and AND are safe on 832.
2278 // So far have seen shortcut requests for
2279 // DIV
2280 // ADD
2281 // RSHIFT
2282 // COMPARE
2283 // SUB
2284 // LSHIFT
2285 // AND
2286 // MULT
2287 // OR
2288
2289// printf("Evaluating shortcut for code %d, type %x\n",code,typ);
2290 if(code==RSHIFT)
2291 return(1);
2292 if(code==AND)
2293 return(1);
2294
2295 return 0;
2296}
2297
2298int reg_parm(struct reg_handle *m, struct Typ *t, int vararg, struct Typ *d)
2299{
2300 int f;
2301 f = t->flags & NQ;
2302 if(is_varargs(d)) /* Disallow register parameters for varargs functions */
2303 return(0);
2304
2305 if (f <= LONG || f == POINTER) {
2306 if (m->gregs >= REGPARM_COUNT)
2307 return 0;
2308 else
2309 return FIRST_GPR + 1 + m->gregs++;
2310 }
2311 if (ISFLOAT(f)) {
2312 return(0);
2313/* if (m->fregs >= 0)
2314 return 0;
2315 else
2316 return FIRST_FPR + 2 + m->fregs++;
2317*/
2318 }
2319 return 0;
2320}
2321
2322int iscomment(char *str)
2323{
2324 char c;
2325 while(c=*str++)
2326 {
2327 if(!c || c=='\n' || c=='/')
2328 return(1);
2329 if(c!=' '&&c!='\t')
2330 return(0);
2331 }
2332 return(1);
2333}
2334
2335
2336int emit_peephole(void)
2337{
2338 int i;
2339 int havemr=0;
2340 int havemt=0;
2341 int havestore=0;
2342 int haveload=0;
2343 int loadidx=0;
2344 i=emit_f;
2345
2346 while(i!=emit_l)
2347 {
2348 int reg,reg2;
2349 if(sscanf(emit_buffer[i],"\tmr\tr%d",&reg)==1)
2350 {
2351 if(havemt && reg==reg2)
2352 {
2353 strcpy(emit_buffer[i],"\t//mr\n");
2354 return(1);
2355 }
2356 reg2=reg;
2357 havemr=1;
2358 havemt=0;
2359 }
2360 else if(sscanf(emit_buffer[i],"\tmt\tr%d",&reg)==1)
2361 {
2362 if(havemr && reg==reg2)
2363 {
2364 strcpy(emit_buffer[i],"\t//mt\n");
2365 return(1);
2366 }
2367 reg2=reg;
2368 havemr=0;
2369 havemt=1;
2370 }
2371 else if(sscanf(emit_buffer[i],"\tst\tr%d",&reg)==1)
2372 {
2373 havemr=havemt=0;
2374 havestore=1;
2375 }
2376 else if(sscanf(emit_buffer[i],"\tld\tr%d",&reg2)==1 && havestore)
2377 {
2378 havemr=havemt=0;
2379 if(reg==reg2 && reg==6) /* Only stack ops - others would be risky due to potential hardware registers. */
2380 {
2381 loadidx=i;
2382 haveload=1;
2383// printf("Found matching load directive, r%d\n",reg);
2384// strcpy(emit_buffer[i],"\t//nop\n");
2385// return(1);
2386 }
2387 }
2388 else if(!iscomment(emit_buffer[i])) /* Check that the next instruction isn't "cond" */
2389 {
2390 havemr=havemt=0;
2391 if(haveload && strncmp(emit_buffer[i],"\tcond",5)) /* If not, we're OK to zero out the load */
2392 {
2393 strcpy(emit_buffer[loadidx],"\t//nop\n");
2394 return(1);
2395 }
2396 else
2397 {
2398 havestore=haveload=0;
2399 }
2400 }
2401 i=(i+1)%EMIT_BUF_DEPTH;
2402 }
2403 return 0;
2404}
2405
2406
2407int handle_pragma(const char *s)
2408{
2409 return(0);
2410}
2411
2412void cleanup_cg(FILE * f)
2413{
2414}
2415
2416void cleanup_db(FILE * f)
2417{
2418 if (f)
2419 section = -1;
2420}