blob: f7b86ac539920ae673fa48b22a8557513bf6fc7f [file] [log] [blame]
PulkoMandy17fc7592022-07-28 18:27:54 +02001/* Example backend for vbcc, it models a generic 32bit RISC or CISC
2 CPU.
3
4 Configurable at build-time are:
5 - number of (32bit) general-purpose-registers
6 - number of (64bit) floating-point-registers
7 - number of (8bit) condition-code-registers
8 - mechanism for stack-arguments (moving ot fixed sp)
9
10 It allows to select as run-time-options:
11 - two- or three-address code
12 - memory operands or load-store-architecture
13 - number of register-arguments
14 - number of caller-save-registers
15*/
16
17#include "supp.h"
18
19static char FILE_[]=__FILE__;
20
21/* Public data that MUST be there. */
22
23/* Name and copyright. */
24char cg_copyright[]="vbcc generic code-generator V0.1b (c) in 2001 by Volker Barthelmann";
25
26/* Commandline-flags the code-generator accepts:
27 0: just a flag
28 VALFLAG: a value must be specified
29 STRINGFLAG: a string can be specified
30 FUNCFLAG: a function will be called
31 apart from FUNCFLAG, all other versions can only be specified once */
32int g_flags[MAXGF]={0,0,
33 VALFLAG,VALFLAG,VALFLAG,
34 0,0,
35 VALFLAG,VALFLAG,0};
36
37/* the flag-name, do not use names beginning with l, L, I, D or U, because
38 they collide with the frontend */
39char *g_flags_name[MAXGF]={"three-addr","load-store",
40 "volatile-gprs","volatile-fprs","volatile-ccrs",
41 "imm-ind","gpr-ind",
42 "gpr-args","fpr-args","use-commons"};
43
44/* the results of parsing the command-line-flags will be stored here */
45union ppi g_flags_val[MAXGF];
46
47/* Alignment-requirements for all types in bytes. */
48zmax align[MAX_TYPE+1];
49
50/* Alignment that is sufficient for every object. */
51zmax maxalign;
52
53/* CHAR_BIT for the target machine. */
54zmax char_bit;
55
56/* sizes of the basic types (in bytes) */
57zmax sizetab[MAX_TYPE+1];
58
59/* Minimum and Maximum values each type can have. */
60/* Must be initialized in init_cg(). */
61zmax t_min[MAX_TYPE+1];
62zumax t_max[MAX_TYPE+1];
63zumax tu_max[MAX_TYPE+1];
64
65/* Names of all registers. will be initialized in init_cg(),
66 register number 0 is invalid, valid registers start at 1 */
67char *regnames[MAXR+1];
68
69/* The Size of each register in bytes. */
70zmax regsize[MAXR+1];
71
72/* a type which can store each register. */
73struct Typ *regtype[MAXR+1];
74
75/* regsa[reg]!=0 if a certain register is allocated and should */
76/* not be used by the compiler pass. */
77int regsa[MAXR+1];
78
79/* Specifies which registers may be scratched by functions. */
80int regscratch[MAXR+1];
81
82/* specifies the priority for the register-allocator, if the same
83 estimated cost-saving can be obtained by several registers, the
84 one with the highest priority will be used */
85int reg_prio[MAXR+1];
86
87/* an empty reg-handle representing initial state */
88struct reg_handle empty_reg_handle={0,0};
89
90/* Names of target-specific variable attributes. */
91char *g_attr_name[]={"__interrupt",0};
92
93
94/****************************************/
95/* Private data and functions. */
96/****************************************/
97
98#define THREE_ADDR (g_flags[0]&USEDFLAG)
99#define LOAD_STORE (g_flags[1]&USEDFLAG)
100#define VOL_GPRS ((g_flags[2]&USEDFLAG)?g_flags_val[2].l:NUM_GPRS/2)
101#define VOL_FPRS ((g_flags[3]&USEDFLAG)?g_flags_val[3].l:NUM_FPRS/2)
102#define VOL_CCRS ((g_flags[4]&USEDFLAG)?g_flags_val[4].l:NUM_CCRS/2)
103#define IMM_IND ((g_flags[5]&USEDFLAG)?1:0)
104#define GPR_IND ((g_flags[6]&USEDFLAG)?2:0)
105#define GPR_ARGS ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:0)
106#define FPR_ARGS ((g_flags[8]&USEDFLAG)?g_flags_val[8].l:0)
107#define USE_COMMONS (g_flags[9]&USEDFLAG)
108
109
110/* alignment of basic data-types, used to initialize align[] */
111static long malign[MAX_TYPE+1]= {1,1,2,4,4,4,4,8,8,1,4,1,1,1,4,1};
112/* sizes of basic data-types, used to initialize sizetab[] */
113static long msizetab[MAX_TYPE+1]={1,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
114
115/* used to initialize regtyp[] */
116static struct Typ ltyp={LONG},ldbl={DOUBLE},lchar={CHAR};
117
118/* macros defined by the backend */
119static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
120 "__GENERIC__",
121 0};
122
123/* special registers */
124static int sp; /* Stackpointer */
125static int t1,t2,t3; /* temporary gprs */
126static int f1,f2,f3; /* temporary fprs */
127
128#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
129static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
130static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
131
132/* sections */
133#define DATA 0
134#define BSS 1
135#define CODE 2
136#define RODATA 3
137#define SPECIAL 4
138
139static long stack;
140static int stack_valid;
141static int section=-1,newobj;
142static char *codename="\t.text\n",
143 *dataname="\t.data\n",
144 *bssname="",
145 *rodataname="\t.section\t.rodata\n";
146
147/* return-instruction */
148static char *ret;
149
150/* label at the end of the function (if any) */
151static int exit_label;
152
153/* assembly-prefixes for labels and external identifiers */
154static char *labprefix="l",*idprefix="_";
155
156#if FIXED_SP
157/* variables to calculate the size and partitioning of the stack-frame
158 in the case of FIXED_SP */
159static long frameoffset,pushed,maxpushed,framesize;
160#else
161/* variables to keep track of the current stack-offset in the case of
162 a moving stack-pointer */
163static long notpopped,dontpop,stackoffset,maxpushed;
164#endif
165
166static long localsize,rsavesize,argsize;
167
168static void emit_obj(FILE *f,struct obj *p,int t);
169
170/* calculate the actual current offset of an object relativ to the
171 stack-pointer; we use a layout like this:
172 ------------------------------------------------
173 | arguments to this function |
174 ------------------------------------------------
175 | return-address [size=4] |
176 ------------------------------------------------
177 | caller-save registers [size=rsavesize] |
178 ------------------------------------------------
179 | local variables [size=localsize] |
180 ------------------------------------------------
181 | arguments to called functions [size=argsize] |
182 ------------------------------------------------
183 All sizes will be aligned as necessary.
184 In the case of FIXED_SP, the stack-pointer will be adjusted at
185 function-entry to leave enough space for the arguments and have it
186 aligned to 16 bytes. Therefore, when calling a function, the
187 stack-pointer is always aligned to 16 bytes.
188 For a moving stack-pointer, the stack-pointer will usually point
189 to the bottom of the area for local variables, but will move while
190 arguments are put on the stack.
191
192 This is just an example layout. Other layouts are also possible.
193*/
194
195static long real_offset(struct obj *o)
196{
197 long off=zm2l(o->v->offset);
198 if(off<0){
199 /* function parameter */
200 off=localsize+rsavesize+4-off-zm2l(maxalign);
201 }
202
203#if FIXED_SP
204 off+=argsize;
205#else
206 off+=stackoffset;
207#endif
208 off+=zm2l(o->val.vmax);
209 return off;
210}
211
212/* Initializes an addressing-mode structure and returns a pointer to
213 that object. Will not survive a second call! */
214static struct obj *cam(int flags,int base,long offset)
215{
216 static struct obj obj;
217 static struct AddressingMode am;
218 obj.am=&am;
219 am.flags=flags;
220 am.base=base;
221 am.offset=offset;
222 return &obj;
223}
224
225/* changes to a special section, used for __section() */
226static int special_section(FILE *f,struct Var *v)
227{
228 char *sec;
229 if(!v->vattr) return 0;
230 sec=strstr(v->vattr,"section(");
231 if(!sec) return 0;
232 sec+=strlen("section(");
233 emit(f,"\t.section\t");
234 while(*sec&&*sec!=')') emit_char(f,*sec++);
235 emit(f,"\n");
236 if(f) section=SPECIAL;
237 return 1;
238}
239
240/* generate code to load the address of a variable into register r */
241static void load_address(FILE *f,int r,struct obj *o,int type)
242/* Generates code to load the address of a variable into register r. */
243{
244 if(!(o->flags&VAR)) ierror(0);
245 if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
246 long off=real_offset(o);
247 if(THREE_ADDR){
248 emit(f,"\tadd.%s\t%s,%s,%ld\n",dt(POINTER),regnames[r],regnames[sp],off);
249 }else{
250 emit(f,"\tmov.%s\t%s,%s\n",dt(POINTER),regnames[r],regnames[sp]);
251 if(off)
252 emit(f,"\tadd.%s\t%s,%ld\n",dt(POINTER),regnames[r],off);
253 }
254 }else{
255 emit(f,"\tmov.%s\t%s,",dt(POINTER),regnames[r]);
256 emit_obj(f,o,type);
257 emit(f,"\n");
258 }
259}
260/* Generates code to load a memory object into register r. tmp is a
261 general purpose register which may be used. tmp can be r. */
262static void load_reg(FILE *f,int r,struct obj *o,int type)
263{
264 type&=NU;
265 if(o->flags&VARADR){
266 load_address(f,r,o,POINTER);
267 }else{
268 if((o->flags&(REG|DREFOBJ))==REG&&o->reg==r)
269 return;
270 emit(f,"\tmov.%s\t%s,",dt(type),regnames[r]);
271 emit_obj(f,o,type);
272 emit(f,"\n");
273 }
274}
275
276/* Generates code to store register r into memory object o. */
277static void store_reg(FILE *f,int r,struct obj *o,int type)
278{
279 type&=NQ;
280 emit(f,"\tmov.%s\t",dt(type));
281 emit_obj(f,o,type);
282 emit(f,",%s\n",regnames[r]);
283}
284
285/* Yields log2(x)+1 or 0. */
286static long pof2(zumax x)
287{
288 zumax p;int ln=1;
289 p=ul2zum(1L);
290 while(ln<=32&&zumleq(p,x)){
291 if(zumeqto(x,p)) return ln;
292 ln++;p=zumadd(p,p);
293 }
294 return 0;
295}
296
297static struct IC *preload(FILE *,struct IC *);
298
299static void function_top(FILE *,struct Var *,long);
300static void function_bottom(FILE *f,struct Var *,long);
301
302#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
303#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
304
305static int q1reg,q2reg,zreg;
306
307static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
308static char *logicals[]={"or","xor","and"};
309static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
310
311/* compare if two objects are the same */
312static int compare_objects(struct obj *o1,struct obj *o2)
313{
314 if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
315 return 1;
316 if(o1->flags==o2->flags&&o1->am==o2->am){
317 if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
318 if(!(o1->flags&REG)||o1->reg==o2->reg){
319 return 1;
320 }
321 }
322 }
323 return 0;
324}
325
326/* Does some pre-processing like fetching operands from memory to
327 registers etc. */
328static struct IC *preload(FILE *f,struct IC *p)
329{
330 int r;
331
332 if(isreg(q1))
333 q1reg=p->q1.reg;
334 else
335 q1reg=0;
336
337 if(isreg(q2))
338 q2reg=p->q2.reg;
339 else
340 q2reg=0;
341
342 if(isreg(z)&&(THREE_ADDR||!compare_objects(&p->q2,&p->z))){
343 zreg=p->z.reg;
344 }else{
345 if(ISFLOAT(ztyp(p)))
346 zreg=f1;
347 else
348 zreg=t1;
349 }
350
351 if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am){
352 p->q1.flags&=~DREFOBJ;
353 load_reg(f,t1,&p->q1,q1typ(p));
354 p->q1.reg=t1;
355 p->q1.flags|=(REG|DREFOBJ);
356 }
357 if(p->q1.flags&&LOAD_STORE&&!isreg(q1)){
358 if(p->code==ASSIGN&&isreg(z))
359 q1reg=p->z.reg;
360 else if(ISFLOAT(q1typ(p)))
361 q1reg=f1;
362 else
363 q1reg=t1;
364 load_reg(f,q1reg,&p->q1,q1typ(p));
365 p->q1.reg=q1reg;
366 p->q1.flags=REG;
367 }
368
369 if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am){
370 p->q2.flags&=~DREFOBJ;
371 load_reg(f,t1,&p->q2,q2typ(p));
372 p->q2.reg=t1;
373 p->q2.flags|=(REG|DREFOBJ);
374 }
375 if(p->q2.flags&&LOAD_STORE&&!isreg(q2)){
376 if(ISFLOAT(q2typ(p)))
377 q2reg=f2;
378 else
379 q2reg=t2;
380 load_reg(f,q2reg,&p->q2,q2typ(p));
381 p->q2.reg=q2reg;
382 p->q2.flags=REG;
383 }
384 return p;
385}
386
387/* save the result (in zreg) into p->z */
388void save_result(FILE *f,struct IC *p)
389{
390 if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
391 p->z.flags&=~DREFOBJ;
392 load_reg(f,t2,&p->z,POINTER);
393 p->z.reg=t2;
394 p->z.flags|=(REG|DREFOBJ);
395 }
396 if(isreg(z)){
397 if(p->z.reg!=zreg)
398 emit(f,"\tmov.%s\t%s,%s\n",dt(ztyp(p)),regnames[p->z.reg],regnames[zreg]);
399 }else{
400 store_reg(f,zreg,&p->z,ztyp(p));
401 }
402}
403
404/* prints an object */
405static void emit_obj(FILE *f,struct obj *p,int t)
406{
407 if(p->am){
408 if(p->am->flags&GPR_IND) emit(f,"(%s,%s)",regnames[p->am->offset],regnames[p->am->base]);
409 if(p->am->flags&IMM_IND) emit(f,"(%ld,%s)",p->am->offset,regnames[p->am->base]);
410 return;
411 }
412 if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
413 emitval(f,&p->val,p->dtyp&NU);
414 return;
415 }
416 if(p->flags&DREFOBJ) emit(f,"(");
417 if(p->flags&REG){
418 emit(f,"%s",regnames[p->reg]);
419 }else if(p->flags&VAR) {
420 if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
421 emit(f,"%ld(%s)",real_offset(p),regnames[sp]);
422 else{
423 if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
424 if(p->v->storage_class==STATIC){
425 emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
426 }else{
427 emit(f,"%s%s",idprefix,p->v->identifier);
428 }
429 }
430 }
431 if(p->flags&KONST){
432 emitval(f,&p->val,t&NU);
433 }
434 if(p->flags&DREFOBJ) emit(f,")");
435}
436
437/* Test if there is a sequence of FREEREGs containing FREEREG reg.
438 Used by peephole. */
439static int exists_freereg(struct IC *p,int reg)
440{
441 while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
442 if(p->code==FREEREG&&p->q1.reg==reg) return 1;
443 p=p->next;
444 }
445 return 0;
446}
447
448/* search for possible addressing-modes */
449static void peephole(struct IC *p)
450{
451 int c,c2,r;struct IC *p2;struct AddressingMode *am;
452
453 for(;p;p=p->next){
454 c=p->code;
455 if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
456 if(c==LABEL) exit_label=p->typf;
457
458 /* Try const(reg) */
459 if(IMM_IND&&(c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
460 int base;zmax of;struct obj *o;
461 eval_const(&p->q2.val,p->typf);
462 if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
463 if(1/*zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))*/){
464 r=p->z.reg;
465 if(isreg(q1)) base=p->q1.reg; else base=r;
466 o=0;
467 for(p2=p->next;p2;p2=p2->next){
468 c2=p2->code;
469 if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
470 if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
471 if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
472 if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
473 if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
474 if(o) break;
475 o=&p2->q1;
476 }
477 if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
478 if(o) break;
479 o=&p2->q2;
480 }
481 if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
482 if(o) break;
483 o=&p2->z;
484 }
485 }
486 if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
487 int m;
488 if(c2==FREEREG)
489 m=p2->q1.reg;
490 else
491 m=p2->z.reg;
492 if(m==r){
493 if(o){
494 o->am=am=mymalloc(sizeof(*am));
495 am->flags=IMM_IND;
496 am->base=base;
497 am->offset=zm2l(of);
498 if(isreg(q1)){
499 p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
500 }else{
501 p->code=c=ASSIGN;p->q2.flags=0;
502 p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
503 }
504 }
505 break;
506 }
507 if(c2!=FREEREG&&m==base) break;
508 continue;
509 }
510 }
511 }
512 }
513 /* Try reg,reg */
514 if(GPR_IND&&c==ADDI2P&&isreg(q2)&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
515 int base,idx;struct obj *o;
516 r=p->z.reg;idx=p->q2.reg;
517 if(isreg(q1)) base=p->q1.reg; else base=r;
518 o=0;
519 for(p2=p->next;p2;p2=p2->next){
520 c2=p2->code;
521 if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
522 if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
523 if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
524 if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
525
526 if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
527 if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
528 if(o||(q1typ(p2)&NQ)==LLONG) break;
529 o=&p2->q1;
530 }
531 if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
532 if(o||(q2typ(p2)&NQ)==LLONG) break;
533 o=&p2->q2;
534 }
535 if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
536 if(o||(ztyp(p2)&NQ)==LLONG) break;
537 o=&p2->z;
538 }
539 }
540 if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
541 int m;
542 if(c2==FREEREG)
543 m=p2->q1.reg;
544 else
545 m=p2->z.reg;
546 if(m==r){
547 if(o){
548 o->am=am=mymalloc(sizeof(*am));
549 am->flags=GPR_IND;
550 am->base=base;
551 am->offset=idx;
552 if(isreg(q1)){
553 p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
554 }else{
555 p->code=c=ASSIGN;p->q2.flags=0;
556 p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
557 }
558 }
559 break;
560 }
561 if(c2!=FREEREG&&m==base) break;
562 continue;
563 }
564 }
565 }
566 }
567}
568
569/* generates the function entry code */
570static void function_top(FILE *f,struct Var *v,long offset)
571{
572 rsavesize=0;
573 if(!special_section(f,v)&&section!=CODE){emit(f,codename);if(f) section=CODE;}
574 if(v->storage_class==EXTERN){
575 if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
576 emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
577 emit(f,"%s%s:\n",idprefix,v->identifier);
578 }else
579 emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
580}
581/* generates the function exit code */
582static void function_bottom(FILE *f,struct Var *v,long offset)
583{
584 emit(f,ret);
585}
586
587/****************************************/
588/* End of private data and functions. */
589/****************************************/
590
591/* Does necessary initializations for the code-generator. Gets called */
592/* once at the beginning and should return 0 in case of problems. */
593int init_cg(void)
594{
595 int i;
596 /* Initialize some values which cannot be statically initialized */
597 /* because they are stored in the target's arithmetic. */
598 maxalign=l2zm(8L);
599 char_bit=l2zm(8L);
600 stackalign=l2zm(4);
601
602 for(i=0;i<=MAX_TYPE;i++){
603 sizetab[i]=l2zm(msizetab[i]);
604 align[i]=l2zm(malign[i]);
605 }
606
607 regnames[0]="noreg";
608 for(i=FIRST_GPR;i<=LAST_GPR;i++){
609 regnames[i]=mymalloc(10);
610 sprintf(regnames[i],"gpr%d",i-FIRST_GPR);
611 regsize[i]=l2zm(4L);
612 regtype[i]=&ltyp;
613 }
614 for(i=FIRST_FPR;i<=LAST_FPR;i++){
615 regnames[i]=mymalloc(10);
616 sprintf(regnames[i],"fpr%d",i-FIRST_FPR);
617 regsize[i]=l2zm(8L);
618 regtype[i]=&ldbl;
619 }
620 for(i=FIRST_CCR;i<=LAST_CCR;i++){
621 regnames[i]=mymalloc(10);
622 sprintf(regnames[i],"ccr%d",i-FIRST_CCR);
623 regsize[i]=l2zm(1L);
624 regtype[i]=&lchar;
625 }
626
627 /* Use multiple ccs. */
628 multiple_ccs=0;
629
630 /* Initialize the min/max-settings. Note that the types of the */
631 /* host system may be different from the target system and you may */
632 /* only use the smallest maximum values ANSI guarantees if you */
633 /* want to be portable. */
634 /* That's the reason for the subtraction in t_min[INT]. Long could */
635 /* be unable to represent -2147483648 on the host system. */
636 t_min[CHAR]=l2zm(-128L);
637 t_min[SHORT]=l2zm(-32768L);
638 t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
639 t_min[LONG]=t_min(INT);
640 t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
641 t_min[MAXINT]=t_min(LLONG);
642 t_max[CHAR]=ul2zum(127L);
643 t_max[SHORT]=ul2zum(32767UL);
644 t_max[INT]=ul2zum(2147483647UL);
645 t_max[LONG]=t_max(INT);
646 t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
647 t_max[MAXINT]=t_max(LLONG);
648 tu_max[CHAR]=ul2zum(255UL);
649 tu_max[SHORT]=ul2zum(65535UL);
650 tu_max[INT]=ul2zum(4294967295UL);
651 tu_max[LONG]=t_max(UNSIGNED|INT);
652 tu_max[LLONG]=zumkompl(ul2zum(0UL));
653 tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
654
655 /* Reserve a few registers for use by the code-generator. */
656 /* This is not optimal but simple. */
657 sp=FIRST_GPR;
658 t1=FIRST_GPR+1;
659 t2=FIRST_GPR+2;
660 f1=FIRST_FPR;
661 f2=FIRST_FPR+1;
662 regsa[t1]=regsa[t2]=1;
663 regsa[f1]=regsa[f2]=1;
664 regsa[sp]=1;
665 regscratch[t1]=regscratch[t2]=0;
666 regscratch[f1]=regscratch[f2]=0;
667 regscratch[sp]=0;
668
669 for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++)
670 regscratch[i]=1;
671 for(i=FIRST_FPR;i<=LAST_FPR-VOL_FPRS;i++)
672 regscratch[i]=1;
673 for(i=FIRST_CCR;i<=LAST_CCR-VOL_CCRS;i++)
674 regscratch[i]=1;
675
676 target_macros=marray;
677
678
679 return 1;
680}
681
682void init_db(FILE *f)
683{
684}
685
686int freturn(struct Typ *t)
687/* Returns the register in which variables of type t are returned. */
688/* If the value cannot be returned in a register returns 0. */
689/* A pointer MUST be returned in a register. The code-generator */
690/* has to simulate a pseudo register if necessary. */
691{
692 if(ISFLOAT(t->flags))
693 return FIRST_FPR+2;
694 if(ISSTRUCT(t->flags)||ISUNION(t->flags))
695 return 0;
696 if(zmleq(szof(t),l2zm(4L)))
697 return FIRST_GPR+3;
698 else
699 return 0;
700}
701
702int reg_pair(int r,struct rpair *p)
703/* Returns 0 if the register is no register pair. If r */
704/* is a register pair non-zero will be returned and the */
705/* structure pointed to p will be filled with the two */
706/* elements. */
707{
708 return 0;
709}
710
711/* estimate the cost-saving if object o from IC p is placed in
712 register r */
713int cost_savings(struct IC *p,int r,struct obj *o)
714{
715 int c=p->code;
716 if(o->flags&VKONST){
717 if(!LOAD_STORE)
718 return 0;
719 if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
720 return 4;
721 else
722 return 2;
723 }
724 if(o->flags&DREFOBJ)
725 return 4;
726 if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
727 if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
728 return 2;
729}
730
731int regok(int r,int t,int mode)
732/* Returns 0 if register r cannot store variables of */
733/* type t. If t==POINTER and mode!=0 then it returns */
734/* non-zero only if the register can store a pointer */
735/* and dereference a pointer to mode. */
736{
737 if(r==0)
738 return 0;
739 t&=NQ;
740 if(t==0&&r>=FIRST_CCR&&r<=LAST_CCR)
741 return 1;
742 if(ISFLOAT(t)&&r>=FIRST_FPR&&r<=LAST_FPR)
743 return 1;
744 if(t==POINTER&&r>=FIRST_GPR&&r<=LAST_GPR)
745 return 1;
746 if(t>=CHAR&&t<=LONG&&r>=FIRST_GPR&&r<=LAST_GPR)
747 return 1;
748 return 0;
749}
750
751int dangerous_IC(struct IC *p)
752/* Returns zero if the IC p can be safely executed */
753/* without danger of exceptions or similar things. */
754/* vbcc may generate code in which non-dangerous ICs */
755/* are sometimes executed although control-flow may */
756/* never reach them (mainly when moving computations */
757/* out of loops). */
758/* Typical ICs that generate exceptions on some */
759/* machines are: */
760/* - accesses via pointers */
761/* - division/modulo */
762/* - overflow on signed integer/floats */
763{
764 int c=p->code;
765 if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
766 return 1;
767 if((c==DIV||c==MOD)&&!isconst(q2))
768 return 1;
769 return 0;
770}
771
772int must_convert(int o,int t,int const_expr)
773/* Returns zero if code for converting np to type t */
774/* can be omitted. */
775/* On the PowerPC cpu pointers and 32bit */
776/* integers have the same representation and can use */
777/* the same registers. */
778{
779 int op=o&NQ,tp=t&NQ;
780 if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
781 return 0;
782 if(op==DOUBLE&&tp==LDOUBLE) return 0;
783 if(op==LDOUBLE&&tp==DOUBLE) return 0;
784 return 1;
785}
786
787void gen_ds(FILE *f,zmax size,struct Typ *t)
788/* This function has to create <size> bytes of storage */
789/* initialized with zero. */
790{
791 if(newobj&&section!=SPECIAL)
792 emit(f,"%ld\n",zm2l(size));
793 else
794 emit(f,"\t.space\t%ld\n",zm2l(size));
795 newobj=0;
796}
797
798void gen_align(FILE *f,zmax align)
799/* This function has to make sure the next data is */
800/* aligned to multiples of <align> bytes. */
801{
802 if(zm2l(align)>1) emit(f,"\t.align\t2\n");
803}
804
805void gen_var_head(FILE *f,struct Var *v)
806/* This function has to create the head of a variable */
807/* definition, i.e. the label and information for */
808/* linkage etc. */
809{
810 int constflag;char *sec;
811 if(v->clist) constflag=is_const(v->vtyp);
812 if(v->storage_class==STATIC){
813 if(ISFUNC(v->vtyp->flags)) return;
814 if(!special_section(f,v)){
815 if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
816 if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
817 if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
818 }
819 if(v->clist||section==SPECIAL){
820 gen_align(f,falign(v->vtyp));
821 emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
822 }else
823 emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
824 newobj=1;
825 }
826 if(v->storage_class==EXTERN){
827 emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
828 if(v->flags&(DEFINED|TENTATIVE)){
829 if(!special_section(f,v)){
830 if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
831 if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&&section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
832 if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
833 }
834 if(v->clist||section==SPECIAL){
835 gen_align(f,falign(v->vtyp));
836 emit(f,"%s%s:\n",idprefix,v->identifier);
837 }else
838 emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
839 newobj=1;
840 }
841 }
842}
843
844void gen_dc(FILE *f,int t,struct const_list *p)
845/* This function has to create static storage */
846/* initialized with const-list p. */
847{
848 emit(f,"\tdc.%s\t",dt(t&NQ));
849 if(!p->tree){
850 if(ISFLOAT(t)){
851 /* auch wieder nicht sehr schoen und IEEE noetig */
852 unsigned char *ip;
853 ip=(unsigned char *)&p->val.vdouble;
854 emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
855 if((t&NQ)!=FLOAT){
856 emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
857 }
858 }else{
859 emitval(f,&p->val,t&NU);
860 }
861 }else{
862 emit_obj(f,&p->tree->o,t&NU);
863 }
864 emit(f,"\n");newobj=0;
865}
866
867
868/* The main code-generation routine. */
869/* f is the stream the code should be written to. */
870/* p is a pointer to a doubly linked list of ICs */
871/* containing the function body to generate code for. */
872/* v is a pointer to the function. */
873/* offset is the size of the stackframe the function */
874/* needs for local variables. */
875
876void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
877/* The main code-generation. */
878{
879 int c,t,i;
880 struct IC *m;
881 argsize=0;
882 if(DEBUG&1) printf("gen_code()\n");
883 for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
884 maxpushed=0;
885
886 /*FIXME*/
887 ret="\trts\n";
888
889 for(m=p;m;m=m->next){
890 c=m->code;t=m->typf&NU;
891 if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
892 if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
893
894 /* convert MULT/DIV/MOD with powers of two */
895 if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
896 eval_const(&m->q2.val,t);
897 i=pof2(vmax);
898 if(i){
899 if(c==MOD){
900 vmax=zmsub(vmax,l2zm(1L));
901 m->code=AND;
902 }else{
903 vmax=l2zm(i-1);
904 if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
905 }
906 c=m->code;
907 gval.vmax=vmax;
908 eval_const(&gval,MAXINT);
909 if(c==AND){
910 insert_const(&m->q2.val,t);
911 }else{
912 insert_const(&m->q2.val,INT);
913 p->typf2=INT;
914 }
915 }
916 }
917#if FIXED_SP
918 if(c==CALL&&argsize<zm2l(m->q2.val.vmax)) argsize=zm2l(m->q2.val.vmax);
919#endif
920 }
921 peephole(p);
922
923 for(c=1;c<=MAXR;c++){
924 if(regsa[c]||regused[c]){
925 BSET(regs_modified,c);
926 }
927 }
928
929 localsize=(zm2l(offset)+3)/4*4;
930#if FIXED_SP
931 /*FIXME: adjust localsize to get an aligned stack-frame */
932#endif
933
934 function_top(f,v,localsize);
935
936#if FIXED_SP
937 pushed=0;
938#endif
939
940 for(;p;p=p->next){
941 c=p->code;t=p->typf;
942 if(c==NOP) {p->z.flags=0;continue;}
943 if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
944 if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
945 if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);continue;}
946 if(c==BRA){
947 if(0/*t==exit_label&&framesize==0*/)
948 emit(f,ret);
949 else
950 emit(f,"\tb\t%s%d\n",labprefix,t);
951 continue;
952 }
953 if(c>=BEQ&&c<BRA){
954 emit(f,"\tb%s\t",ccs[c-BEQ]);
955 if(isreg(q1)){
956 emit_obj(f,&p->q1,0);
957 emit(f,",");
958 }
959 emit(f,"%s%d\n",labprefix,t);
960 continue;
961 }
962 if(c==MOVETOREG){
963 load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
964 continue;
965 }
966 if(c==MOVEFROMREG){
967 store_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
968 continue;
969 }
970 if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
971 ierror(0);
972 }
973 /* switch commutative operands if suitable */
974 if(c==ADD||c==MULT||c==AND||c==XOR||c==OR){
975 if(compare_objects(&p->q2,&p->z)){
976 struct obj tmp;
977 tmp=p->q1;
978 p->q1=p->q2;
979 p->q2=tmp;
980 }
981 }
982
983 p=preload(f,p);
984 c=p->code;
985 if(c==SUBPFP) c=SUB;
986 if(c==ADDI2P) c=ADD;
987 if(c==SUBIFP) c=SUB;
988 if(c==CONVERT){
989 if(ISFLOAT(q1typ(p))||ISFLOAT(ztyp(p))) ierror(0);
990 if(sizetab[q1typ(p)&NQ]<sizetab[ztyp(p)&NQ]){
991 if(q1typ(p)&UNSIGNED)
992 emit(f,"\tzext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
993 else
994 emit(f,"\tsext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
995 }
996 save_result(f,p);
997 continue;
998 }
999 if(c==KOMPLEMENT){
1000 load_reg(f,zreg,&p->q1,t);
1001 emit(f,"\tcpl.%s\t%s\n",dt(t),regnames[zreg]);
1002 save_result(f,p);
1003 continue;
1004 }
1005 if(c==SETRETURN){
1006 load_reg(f,p->z.reg,&p->q1,t);
1007 BSET(regs_modified,p->z.reg);
1008 continue;
1009 }
1010 if(c==GETRETURN){
1011 if(p->q1.reg){
1012 zreg=p->q1.reg;
1013 save_result(f,p);
1014 }else
1015 p->z.flags=0;
1016 continue;
1017 }
1018 if(c==CALL){
1019 int reg;
1020 /*FIXME*/
1021#if 0
1022 if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
1023 if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
1024 stack=framesize+zum2ul(p->q1.v->fi->stack1);
1025 }else
1026 stack_valid=0;
1027#endif
1028 if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
1029 emit_inline_asm(f,p->q1.v->fi->inline_asm);
1030 }else{
1031 emit(f,"\tcall\t");
1032 emit_obj(f,&p->q1,t);
1033 emit(f,"\n");
1034 }
1035 /*FIXME*/
1036#if FIXED_SP
1037 pushed-=zm2l(p->q2.val.vmax);
1038#endif
1039 if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
1040 bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
1041 }else{
1042 int i;
1043 for(i=1;i<=MAXR;i++){
1044 if(regscratch[i]) BSET(regs_modified,i);
1045 }
1046 }
1047 continue;
1048 }
1049 if(c==ASSIGN||c==PUSH){
1050 if(t==0) ierror(0);
1051 if(c==PUSH){
1052#if FIXED_SP
1053 emit(f,"\tmov.%s\t%ld(%s),",dt(t),pushed,regnames[sp]);
1054 emit_obj(f,&p->q1,t);
1055 emit(f,"\n");
1056 pushed+=zm2l(p->q2.val.vmax);
1057#else
1058 emit(f,"\tpush.%s\t",dt(t));
1059 emit_obj(f,&p->q1,t);
1060 emit(f,"\n");
1061 push(zm2l(p->q2.val.vmax));
1062#endif
1063 continue;
1064 }
1065 if(c==ASSIGN){
1066 load_reg(f,zreg,&p->q1,t);
1067 save_result(f,p);
1068 }
1069 continue;
1070 }
1071 if(c==ADDRESS){
1072 load_address(f,zreg,&p->q1,POINTER);
1073 save_result(f,p);
1074 continue;
1075 }
1076 if(c==MINUS){
1077 load_reg(f,zreg,&p->q1,t);
1078 emit(f,"\tneg.%s\t%s\n",dt(t),regnames[zreg]);
1079 save_result(f,p);
1080 continue;
1081 }
1082 if(c==TEST){
1083 emit(f,"\ttst.%s\t",dt(t));
1084 if(multiple_ccs)
1085 emit(f,"%s,",regnames[zreg]);
1086 emit_obj(f,&p->q1,t);
1087 emit(f,"\n");
1088 if(multiple_ccs)
1089 save_result(f,p);
1090 continue;
1091 }
1092 if(c==COMPARE){
1093 emit(f,"\tcmp.%s\t",dt(t));
1094 if(multiple_ccs)
1095 emit(f,"%s,",regnames[zreg]);
1096 emit_obj(f,&p->q1,t);
1097 emit(f,",");
1098 emit_obj(f,&p->q2,t);
1099 emit(f,"\n");
1100 if(multiple_ccs)
1101 save_result(f,p);
1102 continue;
1103 }
1104 if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)){
1105 if(!THREE_ADDR)
1106 load_reg(f,zreg,&p->q1,t);
1107 if(c>=OR&&c<=AND)
1108 emit(f,"\t%s.%s\t%s,",logicals[c-OR],dt(t),regnames[zreg]);
1109 else
1110 emit(f,"\t%s.%s\t%s,",arithmetics[c-LSHIFT],dt(t),regnames[zreg]);
1111 if(THREE_ADDR){
1112 emit_obj(f,&p->q1,t);
1113 emit(f,",");
1114 }
1115 emit_obj(f,&p->q2,t);
1116 emit(f,"\n");
1117 save_result(f,p);
1118 continue;
1119 }
1120 pric2(stdout,p);
1121 ierror(0);
1122 }
1123 function_bottom(f,v,localsize);
1124 if(stack_valid){
1125 if(!v->fi) v->fi=new_fi();
1126 v->fi->flags|=ALL_STACK;
1127 v->fi->stack1=stack;
1128 }
1129 emit(f,"# stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
1130}
1131
1132int shortcut(int code,int typ)
1133{
1134 return 0;
1135}
1136
1137int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
1138{
1139 int f;
1140 f=t->flags&NQ;
1141 if(f<=LONG||f==POINTER){
1142 if(m->gregs>=GPR_ARGS)
1143 return 0;
1144 else
1145 return FIRST_GPR+3+m->gregs++;
1146 }
1147 if(ISFLOAT(f)){
1148 if(m->fregs>=FPR_ARGS)
1149 return 0;
1150 else
1151 return FIRST_FPR+2+m->fregs++;
1152 }
1153 return 0;
1154}
1155
1156int handle_pragma(const char *s)
1157{
1158}
1159void cleanup_cg(FILE *f)
1160{
1161}
1162void cleanup_db(FILE *f)
1163{
1164 if(f) section=-1;
1165}
1166