Import VBCC source snapshot (29/04/2022)
diff --git a/machines/6502/compress.c b/machines/6502/compress.c
new file mode 100644
index 0000000..9295229
--- /dev/null
+++ b/machines/6502/compress.c
@@ -0,0 +1,127 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "vcpr.h"
+
+
+const char tg_copyright[]="6502 code compressor V0.1 (c) 2020 by Volker Barthelmann";
+
+char *inst[]={
+ "lda","ldx","sta","stx","ldy","sty","ldz","stz","ldq","stq",
+ "adc","sbc","and","ora","eor","adcq","sbcq","andq","oraq","eorq",
+ "bne","beq","bcc","bcs","bvs","bvc","bpl","bmi","bra",
+ "clc","sec",
+ /*"pla","pha",*/
+ "txa","tax","tya","tay","tza","taz",
+ "inc","dec","dex","inx","iny","dey","inz","dez","inw","dew","push",
+ /*"rts","rti",*/"jsr","jmp",
+ "cmp","cpx","cpy",
+ "asl","lsr","ror","rol","asw","aslq","lsrq","asr","asrq"
+};
+
+int minsave=5;
+
+void parse_line(char *s,line *p)
+{
+ int l,i;
+ static int secok=0;
+ char buf[16],buf2[16],*e;
+
+ if(sscanf(s," %8s %8s",buf,buf2)==2&&!strcmp(buf,"section")){
+ if(!strcmp(buf2,"text"))
+ secok=1;
+ else
+ secok=0;
+ p->flags=BARRIER;
+ return;
+ }
+
+ if(sscanf(s,"l%d:",&l)==1){
+ p->flags|=LABDEF;
+ p->l1=l;
+ p->size=0;
+ if(!secok) p->flags|=BARRIER;
+ return;
+ }
+
+ if(!secok){
+ p->flags|=BARRIER;
+ return;
+ }
+
+ if(!isspace((unsigned char)*s)){
+ p->flags=BARRIER;
+ return;
+ }
+ while(isspace((unsigned char)*s))
+ s++;
+ for(e=s;isalpha((unsigned char)*e);e++);
+
+ for(i=0;i<sizeof(inst)/sizeof(inst[0]);i++){
+ if(!strncmp(s,inst[i],e-s)){
+ int quad=0;
+ if(e[-1]=='q') quad=2;
+ while(isspace((unsigned char)*e)) e++;
+ if(*e==0){
+ p->size=1;
+ return;
+ }
+ if(*e=='[') p->size++;
+ p->size=2;
+ p->size+=quad;
+ if(sscanf(e,"l%d",&l)==1){
+ p->flags|=LABUSE;
+ p->l1=l;
+ }
+ if(*s=='b'||!strncmp(s,"jmp",3)){
+ p->flags|=BRANCH;
+ }
+ return;
+ }
+ }
+ p->flags=BARRIER;
+}
+
+static int nlab;
+
+#define SECTION "\tsection\ttext\n"
+
+void add_header(line *after)
+{
+ nlab=new_label();
+ line *new;
+ new=new_line();
+ new->flags=LABDEF;
+ new->l1=nlab;
+ new->code=mymalloc(16); /* TODO */
+ sprintf(new->code,"x%d:\n",nlab);
+ insert_line(after,new);
+ new=new_line();
+ new->flags=BARRIER;
+ new->code=mymalloc(strlen(SECTION)+1);
+ strcpy(new->code,SECTION);
+ insert_line(after,new);
+}
+
+void add_ret(line *after)
+{
+ line *new=new_line();
+ new->size=1;
+ new->flags=BARRIER;
+ new->code=mymalloc(8); /*TODO*/
+ strcpy(new->code,"\trts\n");
+ insert_line(after,new);
+}
+
+void add_jsr(line *after)
+{
+ line *new=new_line();
+ new->flags=LABUSE;
+ new->size=3;
+ new->l1=nlab;
+ new->code=mymalloc(24); /* TODO */
+ sprintf(new->code,"\tjsr\tx%d\n",nlab);
+ insert_line(after,new);
+}
diff --git a/machines/6502/machine.c b/machines/6502/machine.c
new file mode 100755
index 0000000..c8e14b6
--- /dev/null
+++ b/machines/6502/machine.c
@@ -0,0 +1,6029 @@
+/* 6502 backend for vbcc
+ (c) Volker Barthelmann 2020
+
+*/
+
+#include "supp.h"
+#include "vbc.h"
+
+#include <math.h>
+
+static char FILE_[]=__FILE__;
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc 6502 code-generator V0.5 (c) in 2022 by Volker Barthelmann";
+
+/* Commandline-flags the code-generator accepts:
+ 0: just a flag
+ VALFLAG: a value must be specified
+ STRINGFLAG: a string can be specified
+ FUNCFLAG: a function will be called
+ apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]={0,0,
+ VALFLAG,0,0,
+ 0,0,
+ VALFLAG,VALFLAG,0,0,
+ VALFLAG,0,0,0,
+ 0,0,0,
+ 0,0,0,0,0,0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+ they collide with the frontend */
+char *g_flags_name[MAXGF]={"std-syntax","no-rax",
+ "volatile-regs","ieee","no-peephole",
+ "cbmascii","softstack",
+ "reg-args","int-args","mainargs","no-bank-vars",
+ "common-banknr","btmp-zpage","oldfp","large",
+ "glob-acc","avoid-bank-switch","manual-banking",
+ "atascii","65c02","nox","mega65","ce02","c02",
+ "div-bug","m65io"};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. will be initialized in init_cg(),
+ register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+ estimated cost-saving can be obtained by several registers, the
+ one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__interrupt","__zpage","__nocpr",0};
+
+#define INTERRUPT 1
+#define ZPAGE 2
+#define NOCOMPRESS 4
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+#define STDSYNTAX (g_flags[0]&USEDFLAG)
+#define NORAX (g_flags[1]&USEDFLAG)
+#define VOL_GPRS ((g_flags[2]&USEDFLAG)?g_flags_val[2].l:NUM_GPRS/2)
+#define IEEE (g_flags[3]&USEDFLAG)
+#define NOPEEP (g_flags[4]&USEDFLAG)
+#define CBMASCII (g_flags[5]&USEDFLAG)
+#define SOFTSTACK (g_flags[6]&USEDFLAG)
+#define GPR_ARGS ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:8)
+#define MAINARGS (g_flags[9]&USEDFLAG)
+#define NOBANKVARS (g_flags[10]&USEDFLAG)
+#define COMMONBANK ((g_flags[11]&USEDFLAG)?g_flags_val[11].l:0)
+#define BIGZPAGE (g_flags[12]&USEDFLAG)
+#define OLDFP (g_flags[13]&USEDFLAG)
+#define LARGE (g_flags[14]&USEDFLAG)
+#define GLOBACC (g_flags[15]&USEDFLAG)
+#define NOSWITCH (g_flags[16]&USEDFLAG)
+#define NOBANKING (g_flags[17]&USEDFLAG)
+#define ATASCII (g_flags[18]&USEDFLAG)
+#define C02 (g_flags[19]&USEDFLAG)
+#define NOX (g_flags[20]&USEDFLAG)
+#define MEGA65 (g_flags[21]&USEDFLAG)
+#define CE02 (g_flags[22]&USEDFLAG)
+#define C02ALT (g_flags[23]&USEDFLAG)
+#define DIVBUG (g_flags[24]&USEDFLAG)
+#define M65IO (g_flags[25]&USEDFLAG)
+
+
+
+#define STR_NEAR "near"
+#define STR_FAR "far"
+#define STR_HUGE "huge"
+
+#define PLA (-1)
+#define JMPIND (-2)
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isacc(x) (isreg(x)&&(p->x.reg==ra||p->x.reg==rax))
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+#define iszpage(o) (((o)->flags&(REG|DREFOBJ))==REG||(((o)->flags&(VAR|DREFOBJ))==VAR&&(o)->v->tattr&ZPAGE))
+
+#define isptr(r) ((r)>=FIRST_PAIR&&(r)<=LAST_PAIR)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"ora","eor","and"};
+static char *arithmetics[]={"slw","srw","adc","sbc","mullw","divw","mod"};
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]= {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,2,4,8,4,4,4,0,2,3,3,0,0,0,1,0};
+static char *mregnames[MAXR+1+4];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","char","short","int","long","long long",
+ "float","double","long double","void",
+ "near-pointer","far-pointer","huge-pointer",
+ "array","struct","union","enum","function"};
+
+
+/* used to initialize regtyp[] */
+static struct Typ ityp={INT},ctyp={CHAR},ftyp={FLOAT},lltyp={LLONG};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+ "__6502__",
+ "__SIZE_T_INT",
+ "__bank(x)=__vattr(\"bank(\"#x\")\")",
+ "__far=__attr(\"far\")",
+ "__near=__attr(\"near\")",
+ "__huge=__attr(\"huge\")",
+ 0};
+
+/* special registers */
+static int ra=1, rx=2, ry=3, sp1=4,sp2=5,sp=6,fp,fp1,fp2;
+static int t4=LAST_GPR,t3=LAST_GPR-1,t2=LAST_GPR-2,t1=LAST_GPR-3;
+static int rax=7;
+static int yval;
+#define NOVAL 1000
+
+#define REGDUMMY1 MAXR+1
+#define REGDUMMY2 MAXR+2
+#define REGDUMMY3 MAXR+3
+
+static int t1,t2,f1,f2; /*tODO: remove*/
+
+static int pushedacc,pushedx,nopeep,cbmascii,atascii,ieee;
+static int storedacc,storedx;
+static int c02,m65,ce02,zzero,noy;
+static int divbug;
+static int m65io;
+static int manbank;
+static char *jmpinst;
+static int pass;
+static int libsave;
+static struct rpair rp2;
+static int cbank;
+static Var bankv;
+static int bankvoffset;
+static int bankcnum;
+static obj zstore;
+static int zstoreflag;
+static int hasretval;
+
+#define SECLEN 128
+char *use_sec;
+int use_bank=-1;
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* perhaps provide version with 8bit int? */
+#define ISCHAR(t) ((t&NQ)==CHAR)
+#define ISSHORT(t) ((t&NQ)==SHORT||(t&NQ)==INT||(t&NQ)==POINTER)
+#define ISFPOINTER(t) ((t&NQ)==FPOINTER)
+#define ISLONG(t) ((t&NQ)==LONG)
+#define ISLLONG(t) ((t&NQ)==LLONG)
+
+#define ISIDX(r) (r==rx)
+#define ISRIDX(op) (isreg(op)&&ISIDX(p->op.reg))
+#define ISPREG(op) (isreg(op)&&isptr(p->op.reg))
+
+#define LONGM65(c) ((c)==ASSIGN||(c)==PUSH||(c)==GETRETURN||(c)==SETRETURN||((c)>=LSHIFT&&(c)<=MOD)||((c)>=OR&&(c)<=AND))
+
+/* am */
+#define IMM_IND 1
+#define GPR_IND 2
+#define ABS_IND 3
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\tsection\ttext",
+ *dataname="\tsection\tdata",
+ *bssname="\tsection\tbss",
+ *rodataname="\tsection\trodata";
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+/* variables to calculate the size and partitioning of the stack-frame
+ in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+
+static long localsize,rsavesize,rscnt,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+ stack-pointer; we use a layout like this:
+ ------------------------------------------------
+ | arguments to this function |
+ ------------------------------------------------
+ | caller-save registers [size=rsavesize] |
+ ------------------------------------------------
+ | local variables [size=localsize] |
+ ------------------------------------------------
+ | arguments to called functions [size=argsize] |
+ ------------------------------------------------
+ All sizes will be aligned as necessary.
+ In the case of FIXED_SP, the stack-pointer will be adjusted at
+ function-entry to leave enough space for the arguments and have it
+ aligned to 16 bytes. Therefore, when calling a function, the
+ stack-pointer is always aligned to 16 bytes.
+ For a moving stack-pointer, the stack-pointer will usually point
+ to the bottom of the area for local variables, but will move while
+ arguments are put on the stack.
+
+ This is just an example layout. Other layouts are also possible.
+*/
+
+#define bank(x) bankx((x),manbank)
+#define sbank(x) bankx((x),0)
+
+static int bankx(Var *v,int nobank)
+{
+ char *s=v->vattr;
+ int n,r;
+ if(!nobank&&s&&(s=strstr(s,"bank("))){
+ if(sscanf(s+5,"%i",&n)==1)
+ return n;
+ }
+ return -1;
+}
+
+static void ebank(FILE *f,int b)
+{
+ if(b>=0) emit(f,"%d",b);
+ emit(f,"\n");
+}
+
+static long real_offset(struct obj *o)
+{
+ long off=zm2l(o->v->offset);
+ if(off<0){
+ /* function parameter */
+ off=localsize+rsavesize-off-zm2l(maxalign);
+ }
+
+ off+=argsize;
+ off+=zm2l(o->val.vmax);
+ return off;
+}
+
+/* Initializes an addressing-mode structure and returns a pointer to
+ that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ am.offset=offset;
+ return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+ char *sec;
+ if(v->tattr&ZPAGE){
+ emit(f,"\tsection\tzpage\n");
+ }else{
+ if(!v->vattr) return 0;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return 0;
+ sec+=strlen("section(");
+ emit(f,"\tsection\t");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ }
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+
+
+#define chk_coll(x) do{if((x)==r||(x)==r1||(x)==r2) return 0; \
+ if(reg_pair((x),&rp)&&(rp.r1==r||rp.r2==r)) return 0;}while(0)
+
+static int scratch(IC *p,int r,int isnext)
+{
+ int r1,r2;
+ if(!p) return 1;
+ if(reg_pair(r,&rp)){
+ r1=rp.r1;
+ r2=rp.r2;
+ }else{
+ r1=0;
+ r2=0;
+ }
+ if(!isnext&&isreg(z)&&p->z.reg==r){
+ if(!(p->q2.flags®))
+ return 1;
+ if(p->q2.reg==r||p->q2.reg==r1||p->q2.reg==r2)
+ return 0;
+ if(reg_pair(p->q2.reg,&rp))
+ if(rp.r1==r||rp.r2==r)
+ return 0;
+ return 1;
+ }
+ while(p){
+ if(p->code==LABEL||p->code==CALL)
+ return 0;
+ if(p->code>=BEQ&&p->code<=BRA)
+ return 0;
+ if(p->code==FREEREG||p->code==ALLOCREG){
+ if(p->q1.reg==r)
+ return 1;
+ if(reg_pair(p->q1.reg,&rp)&&(rp.r1==r||rp.r2==r))
+ return 1;
+ }
+ if(p->q1.am){
+ chk_coll(p->q1.am->base);
+ if(p->q1.am->flags!=IMM_IND) chk_coll(p->q1.am->idx);
+ }
+ if(p->q2.am){
+ chk_coll(p->q2.am->base);
+ if(p->q2.am->flags!=IMM_IND) chk_coll(p->q2.am->idx);
+ }
+ if(p->z.am){
+ chk_coll(p->z.am->base);
+ if(p->z.am->flags!=IMM_IND) chk_coll(p->z.am->idx);
+ }
+ if(p->q1.flags®) chk_coll(p->q1.reg);
+ if(p->q2.flags®) chk_coll(p->q2.reg);
+ if(p->z.flags®){
+ if(p->z.flags&DREFOBJ)
+ chk_coll(p->z.reg);
+ else{
+ if(p->z.reg==r)
+ return 1;
+ if(reg_pair(p->z.reg,&rp)&&(rp.r1==r||rp.r2==r))
+ return 1;
+ }
+ }
+
+ p=p->next;
+ }
+ return 1;
+}
+
+static int rsavecur;
+static int in_isr;
+
+static int get_reg(FILE *f,IC *p,int t)
+{
+ int r,r1,r2,pass,flag;
+
+ for(pass=0;pass<5;pass++){
+ for(r=MAXR;r>sp;r--){
+ if(reg_pair(r,&rp)){
+ r1=rp.r1;
+ r2=rp.r2;
+ }else{
+ r1=0;
+ r2=0;
+ }
+ if((pass==0||pass==3)&&(!regscratch[r]||in_isr))
+ continue;
+ if(pass<3){
+ if(regs[r]) continue;
+ if(r1&&(regs[r1]||regs[r2])) continue;
+ }
+ if(pass==2&&!(regs[r]&4))
+ continue;
+ if(p->q1.flags®){
+ if(p->q1.reg==r||p->q1.reg==r1||p->q1.reg==r2) continue;
+ if(r1==0&®_pair(p->q1.reg,&rp)&&(rp.r1==r||rp.r2==r)) continue;
+ }
+ if(p->q2.flags®){
+ if(p->q2.reg==r||p->q2.reg==r1||p->q2.reg==r2) continue;
+ if(r1==0&®_pair(p->q2.reg,&rp)&&(rp.r1==r||rp.r2==r)) continue;
+ }
+ if(p->z.flags®){
+ if(p->z.reg==r||p->z.reg==r1||p->z.reg==r2) continue;
+ if(r1==0&®_pair(p->z.reg,&rp)&&(rp.r1==r||rp.r2==r)) continue;
+ }
+ if(regok(r,t,1)){
+ flag=8;
+ if(regs[r]){
+ flag|=2;
+ if(p->code==COMPARE||p->code==TEST)
+ ierror(0);
+ if(regs[ra]){
+ emit(f,"\ttay\n");
+ yval=NOVAL;
+ }
+ if(r1){
+ emit(f,"\tlda\t%s\n",mregnames[r1]);
+ emit(f,"\tpha\n");
+ emit(f,"\tlda\t%s\n",mregnames[r2]);
+ emit(f,"\tpha\n");
+ }else{
+ emit(f,"\tlda\t%s\n",mregnames[r]);
+ emit(f,"\tpha\n");
+ }
+ if(regs[ra])
+ emit(f,"\ttya\n");
+ }
+ if(r1){
+ regs[r1]|=flag;
+ regs[r2]|=flag;
+ }
+ regs[r]|=flag;
+ regused[r]=1;
+ regused[r1]=1;
+ regused[r2]=1;
+ /*emit(f,"; p=%p r=%s\n",(void*)p,mregnames[r]);*/
+ return r;
+ }
+ }
+ }
+ pric2(stdout,p);
+ ierror(0);
+}
+
+static void get_acc(FILE *f, IC *p,int t)
+{
+ int r;
+ if(isacc(z)) return;
+ t&=NQ;
+ if(ISCHAR(t)){
+ if(1/*!isreg(q1)||(p->q1.reg!=ra&&p->q1.reg!=rax)*/){
+ if((regs[ra]||regs[rax])&&!scratch(p,ra,0)&&!pushedacc){
+ if(storedacc)
+ pushedacc=storedacc;
+ else if(optsize||(regs[t1]&®s[t2]&®s[t3]&®s[t4])){
+ emit(f,"\tpha\n");
+ pushedacc=-1;
+ }else{
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ pushedacc=r;
+ }
+ }
+ }
+ }else{
+ if(1/*!isreg(q1)||p->q1.reg!=rax*/){
+ if((regs[ra]||regs[rax])&&(!scratch(p,ra,0)||!scratch(p,rax,0))&&!pushedacc){
+ if(!storedacc){
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ pushedacc=r;
+ }else
+ pushedacc=storedacc;
+ }
+ if((regs[rx]||regs[rax])&&!scratch(p,rax,0)&&!pushedx){
+ if(!storedx){
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tstx\t%s\n",mregnames[r]);
+ pushedx=r;
+ }else
+ pushedx=storedx;
+ }
+ }
+ }
+}
+
+static int cmp_get_acc(FILE *f,IC *p,IC *branch)
+{
+ if(!regs[ra]&&!regs[rax])
+ return 0;
+ if(branch==0&&pushedacc)
+ return 0;
+ if(branch&&isreg(q1)&&(p->q1.reg==ra||p->q1.reg==rax))
+ if(branch->code==BEQ||branch->code==BNE||(p->typf&UNSIGNED))
+ return 0;
+ if(scratch(p,ra,0))
+ return 0;
+ if(!regs[rx]&&!regs[rax]){
+ emit(f,"\ttax\n");
+ pushedacc=rx;
+ }
+ emit(f,"\tpha\n");
+ pushedacc=-1;
+ return pushedacc;
+}
+
+static void reload_acc_opt(FILE *f,IC *p)
+{
+ if(pushedacc==0) return;
+ if(pushedacc>0){
+ while(p){
+ if(p->code!=FREEREG) break;
+ if(p->q1.reg==ra||p->q1.reg==rax){
+ pushedacc=0;
+ return;
+ }
+ p=p->next;
+ }
+ }
+ if(pushedacc==-1)
+ emit(f,"\tpla\n");
+ else if(pushedacc==rx)
+ emit(f,"\ttxa\n");
+ else if(pushedacc==ry)
+ emit(f,"\ttya\n");
+ else if(pushedacc){
+ emit(f,"\tlda\t%s\n",mregnames[pushedacc]);
+ regs[pushedacc]&=~8;
+ }
+ pushedacc=0;
+}
+
+static void reload_acc(FILE *f)
+{
+ reload_acc_opt(f,0);
+}
+
+static void push(int i)
+{
+ pushed-=i;
+ if(pushed<maxpushed)
+ maxpushed=pushed;
+}
+
+static void pop(int i)
+{
+ pushed+=i;
+ if(pushed>0) ierror(0);
+}
+
+static int indirect(obj *o)
+{
+ if(o->am){
+ if(o->am->flags==ABS_IND&&o->am->idx==rx)
+ return 0;
+ else
+ return 1;
+ }
+ if((o->flags&(DREFOBJ|KONST))==DREFOBJ)
+ return 1;
+ if((o->flags&(REG|VAR))!=VAR){
+ if((o->flags®)&&(o->reg==ra||ISIDX(o->reg)||o->reg==rax))
+ return 1;
+ return 0;
+ }
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)
+ return 1;
+ return 0;
+}
+
+void convfloat(void)
+{
+}
+
+void sety(FILE *f,int val)
+{
+ if(yval==val)
+ return;
+ if(val-yval==1)
+ emit(f,"\tiny\n");
+ else if(yval-val==1)
+ emit(f,"\tdey\n");
+ else{
+ emit(f,"\tldy\t#%d\n",val);
+ if(val<0||val>255)
+ ierror(0);
+ }
+ yval=val;
+}
+
+static void cnv_fp(void)
+{
+ double d,mant;
+ int exp;
+ unsigned long t;
+
+ if(ieee){
+ vfloat=zld2zf(vldouble);
+ memcpy((void*)&vmax,(void*)&vfloat,4);
+ }else{
+ d=zld2d(vldouble);
+ mant=frexp(d,&exp);
+ exp=(exp+127)&255;
+ t=((unsigned long)(mant*8388608))&0xffffff;
+ t|=((long)exp)<<24;
+
+ t=((t&0xff)<<24)|((t&0xff00)<<8)|((t&0xff0000)>>8)|((t&0xff000000)>>24);
+ vmax=l2zm((long)t);
+ if(mant==0&&d==0) vmax=Z0;
+ }
+}
+
+static void emit_ieee(FILE *f,union atyps *p,int t)
+{
+ unsigned char *ip=(unsigned char *)&p->vdouble;
+ emit(f,"0x%02x%02x,0x%02x%02x",ip[1],ip[0],ip[3],ip[2]);
+ if(t==DOUBLE||t==LDOUBLE)
+ emit(f,",0x%02x%02x,0x%02x%02x",ip[5],ip[4],ip[7],ip[6]);
+ emit(f,"\n");
+}
+
+static void emit_lobyte(FILE *f,obj *o,int t)
+{
+ if(o->flags&KONST){
+ if(o->flags&DREFOBJ){
+ eval_const(&o->val,o->dtyp);
+ emit(f,"%d",zm2l(vmax));
+ }else{
+ eval_const(&o->val,t);
+ if(ISFLOAT(t)) cnv_fp();
+ emit(f,"#%d",zm2l(vmax)&255);
+ }
+ }else if(o->flags&VARADR){
+ emit(f,"#<(");
+ emit_obj(f,o,t);
+ emit(f,")");
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ if(!reg_pair(o->reg,&rp))
+ emit(f,"%s",mregnames[o->reg]);
+ else
+ emit(f,"%s",mregnames[rp.r1]);
+ }else{
+ if(zzero&&(o->flags&(DREFOBJ|KONST))==DREFOBJ) noy=1;
+ emit_obj(f,o,t);
+ noy=0;
+ }
+}
+
+static void emit_hibyte(FILE *f,obj *o,int t)
+{
+ if(o->flags&KONST){
+ if(o->flags&DREFOBJ){
+ eval_const(&o->val,o->dtyp);
+ emit(f,"%d",zm2l(vmax)+1);
+ }else{
+ eval_const(&o->val,t);
+ if(ISFLOAT(t)) cnv_fp();
+ emit(f,"#%d",(zm2l(vmax)>>8)&255);
+ }
+ }else if(o->flags&VARADR){
+ emit(f,"#>(");
+ emit_obj(f,o,t);
+ emit(f,")");
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg>=FIRST_BIG&&o->reg<=LAST_BIGP){
+ emit(f,"%s+1",mregnames[o->reg]);
+ }else{
+ if(!reg_pair(o->reg,&rp))
+ ierror(0);
+ emit(f,"%s",mregnames[rp.r2]);
+ }
+ }else{
+ if(o->flags&VARADR)
+ emit(f,"#");
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmadd(o->val.vmax,Z1);
+ emit_obj(f,o,t);
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmsub(o->val.vmax,Z1);
+ }
+}
+
+static void emit_byte3(FILE *f,obj *o,int t)
+{
+ if(o->flags&KONST){
+ if(o->flags&DREFOBJ){
+ eval_const(&o->val,o->dtyp);
+ emit(f,"%d",zm2l(vmax)+2);
+ }else{
+ eval_const(&o->val,t);
+ if(ISFLOAT(t)) cnv_fp();
+ emit(f,"#%d",(zm2l(vmax)>>16)&255);
+ }
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ emit(f,"%s+2",mregnames[o->reg]);
+ }else if(o->flags&VARADR){
+ emit(f,"#%d",bank(o->v));
+ }else{
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmadd(o->val.vmax,l2zm(2L));
+ emit_obj(f,o,t);
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmsub(o->val.vmax,l2zm(2L));
+ }
+}
+
+static void emit_byte4(FILE *f,obj *o,int t)
+{
+ if(o->flags&KONST){
+ if(o->flags&DREFOBJ){
+ eval_const(&o->val,o->dtyp);
+ emit(f,"%d",zm2l(vmax)+3);
+ }else{
+ eval_const(&o->val,t);
+ if(ISFLOAT(t)) cnv_fp();
+ emit(f,"#%d",(zm2l(vmax)>>24)&255);
+ }
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ emit(f,"%s+3",mregnames[o->reg]);
+ }else{
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmadd(o->val.vmax,l2zm(3L));
+ emit_obj(f,o,t);
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmsub(o->val.vmax,l2zm(3L));
+ }
+}
+
+static void ldq_offset(FILE *f,obj *o)
+{
+ if(o->am){
+ if(o->am->flags==IMM_IND)
+ emit(f,"\tldz\t#%ld\n",o->am->offset);
+ else if(o->am->flags==GPR_IND||o->am->flags==ABS_IND){
+ if(o->am->idx==ra)
+ emit(f,"\ttaz\n");
+ else{
+ if(ISIDX(o->am->idx)){
+ if(o->am->flags==GPR_IND){
+ emit(f,"\tpha\n");
+ emit(f,"\tt%sa\n",mregnames[o->am->idx]);
+ emit(f,"\ttaz\n");
+ emit(f,"\tpla\n");
+ }
+ }else
+ emit(f,"\tldz\t%s\n",mregnames[o->am->idx]);
+ }
+ }else
+ ierror(0);
+ }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+ /*if(!zzero)*/ emit(f,"\tldz\t#0\n");
+ }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+ emit(f,"\tldz\t#%ld\n",real_offset(o));
+ }
+}
+
+static void do_amload(FILE *f,obj *o)
+{
+ if(o->am->flags==GPR_IND||o->am->flags==ABS_IND){
+ if(o->am->idx==ra)
+ emit(f,"\ttay\n");
+ else{
+ if(ISIDX(o->am->idx)){
+ if(o->am->flags==GPR_IND){
+ emit(f,"\tpha\n");
+ emit(f,"\tt%sa\n",mregnames[o->am->idx]);
+ emit(f,"\ttay\n");
+ emit(f,"\tpla\n");
+ }
+ }else{
+ if(o->am->idx==ra)
+ emit(f,"\ttay\n");
+ else
+ emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+ }
+ }
+ }else
+ ierror(0);
+}
+static void do_lobyte(FILE *f,char *s,obj *o,int type)
+{
+ if(o->am){
+ if(o->am->flags==IMM_IND)
+ sety(f,o->am->offset);
+ else{
+ do_amload(f,o);
+ yval=NOVAL;
+ }
+ }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+ if(!zzero) sety(f,0);
+ }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+ sety(f,(int)real_offset(o));
+ }
+ emit(f,"\t%s\t",s);
+ emit_lobyte(f,o,type);
+ emit(f,"\n");
+}
+
+static void do_hibyte(FILE *f,char *s,obj *o,int type)
+{
+ int ami=0;
+ if(o->am){
+ if(o->am->flags==IMM_IND)
+ sety(f,o->am->offset+1);
+ else{
+ do_amload(f,o);
+ if(o->am->flags==GPR_IND){
+ emit(f,"\tiny\n");
+ }else{
+ o->am->offset++;ami=1;
+ }
+ yval=NOVAL;
+ }
+ }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+ sety(f,1);
+ }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+ sety(f,(int)real_offset(o)+1);
+ }
+ emit(f,"\t%s\t",s);
+ emit_hibyte(f,o,type);
+ emit(f,"\n");
+ if(ami) o->am->offset--;
+}
+
+static void do_byte3(FILE *f,char *s,obj *o,int type)
+{
+ int ami=0;
+ if(o->am){
+ if(o->am->flags==IMM_IND)
+ sety(f,o->am->offset+2);
+ else{
+ do_amload(f,o);
+ if(o->am->flags==GPR_IND){
+ emit(f,"\tiny\n\tiny\n");
+ }else{
+ o->am->offset+=2;ami=1;
+ }
+ yval=NOVAL;
+ }
+ }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+ sety(f,2);
+ }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+ sety(f,(int)real_offset(o)+2);
+ }
+ emit(f,"\t%s\t",s);
+ emit_byte3(f,o,type);
+ emit(f,"\n");
+ if(ami) o->am->offset-=2;
+}
+
+static void do_byte4(FILE *f,char *s,obj *o,int type)
+{
+ int ami=0;
+ if(o->am){
+ if(o->am->flags==IMM_IND)
+ sety(f,o->am->offset+3);
+ else{
+ do_amload(f,o);
+ if(o->am->flags==GPR_IND){
+ emit(f,"\tiny\n\tiny\n\tiny\n");
+ }else{
+ o->am->offset+=3;ami=1;
+ }
+ yval=NOVAL;
+ }
+ }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+ sety(f,3);
+ }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+ sety(f,(int)real_offset(o)+3);
+ }
+ emit(f,"\t%s\t",s);
+ emit_byte4(f,o,type);
+ emit(f,"\n");
+ if(ami) o->am->offset-=3;
+}
+
+static void load_lobyte(FILE *f,obj *o,int t)
+{
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg==ra||o->reg==rax)
+ return;
+ if(o->reg==rx){
+ emit(f,"\ttxa\n");
+ return;
+ }
+ }
+ do_lobyte(f,"lda",o,t);
+}
+
+static void load_hibyte(FILE *f,obj *o,int t)
+{
+ if((o->flags®)&&(o->reg==rx||o->reg==rax))
+ emit(f,"\ttxa\n");
+ else
+ do_hibyte(f,"lda",o,t);
+}
+
+static void store_lobyte(FILE *f,obj *o,int t)
+{
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg==ra||o->reg==rax)
+ return;
+ if(o->reg==rx){
+ emit(f,"\ttax\n");
+ return;
+ }
+ }
+ do_lobyte(f,"sta",o,t);
+}
+
+static void store_hibyte(FILE *f,obj *o,int t)
+{
+ if((o->flags®)&&(o->reg==rx||o->reg==rax))
+ emit(f,"\ttax\n");
+ else
+ do_hibyte(f,"sta",o,t);
+}
+
+static void load_acc(FILE *f,obj *o,int type)
+{
+ if((o->flags®)&&(o->reg==ra||o->reg==rax))
+ return;
+ if(!ISCHAR(type)){
+ if(indirect(o)){
+ do_hibyte(f,"lda",o,type);
+ emit(f,"\ttax\n");
+ }else
+ do_hibyte(f,"ldx",o,type);
+ }
+ if((o->flags&(REG|DREFOBJ))==REG&&o->reg==rx)
+ emit(f,"\ttxa\n");
+ else
+ do_lobyte(f,"lda",o,type);
+}
+
+static void store_acc(FILE *f,obj *o,int type)
+{
+ if((o->flags&(DREFOBJ|KONST))==DREFOBJ&&((!(o->flags®))||!isptr(o->reg))){
+ ierror(0);
+ }
+ if((o->flags®)&&(o->reg==ra||o->reg==rax))
+ return;
+ if((o->flags®)&&o->reg==rx){
+ emit(f,"\ttax\n");
+ return;
+ }
+ store_lobyte(f,o,type);
+ if(!ISCHAR(type)){
+ if(indirect(o)){
+ /*TODO: save accu */
+ emit(f,"\ttxa\n");
+ store_hibyte(f,o,type);
+ }else
+ do_hibyte(f,"stx",o,type);
+ }
+}
+
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+ static obj ro;
+ if(ISIDX(r)&&!indirect(o)){
+ static char ldr[4]="ldr";
+ ldr[2]=mregnames[r][0];
+ do_lobyte(f,ldr,o,type);
+ return;
+ }
+ ro.flags=REG;
+ ro.reg=r;
+ load_lobyte(f,o,type);
+ store_lobyte(f,&ro,type);
+ if(!ISCHAR(type)){
+ load_hibyte(f,o,type);
+ store_hibyte(f,&ro,type);
+ }
+}
+
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+ static obj ro;
+ if(ISIDX(r)){
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg==r)
+ return;
+ if(o->reg==ra){
+ emit(f,"\tt%sa\n",mregnames[r]);
+ return;
+ }
+ }
+ if(!indirect(o)){
+ static char str[4]="str";
+ str[2]=mregnames[r][0];
+ do_lobyte(f,str,o,type);
+ return;
+ }
+ }
+ ro.flags=REG;
+ ro.reg=r;
+ if(r!=ra&&r!=rax)
+ load_acc(f,&ro,type);
+ store_acc(f,o,type);
+}
+
+static struct fpconstlist {
+ struct fpconstlist *next;
+ int label;
+ int t;
+ union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+ struct fpconstlist *p=firstfpc;
+ t&=NQ;
+ if(t==LDOUBLE) t=DOUBLE;
+ for(p=firstfpc;p;p=p->next){
+ if(t==p->t){
+ eval_const(&p->val,t);
+ if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+ if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+ if(t==LONG&&zmeqto(vmax,zl2zm(o->val.vlong))) return p->label;
+ if(t==LLONG&&zmeqto(vmax,zll2zm(o->val.vllong))) return p->label;
+ }
+ }
+ p=mymalloc(sizeof(struct fpconstlist));
+ p->next=firstfpc;
+ p->t=t;
+ p->label=++label;
+ p->val=o->val;
+ firstfpc=p;
+ return p->label;
+}
+
+/* generate code to load the address of a local variable into register r */
+static void load_laddr(FILE *f,int r,struct obj *o)
+{
+ long l=real_offset(o);
+ /* assumes acc is available */
+ if(!reg_pair(r,&rp)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[fp]);
+ if(l!=0)
+ emit(f,"\tclc\n");
+ if(l&255)
+ emit(f,"\tadc\t#%ld\n",l&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[fp2]);
+ if(l!=0)
+ emit(f,"\tadc\t#%ld\n",(l>>8)&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int t)
+{
+ if(o->flags&DREFOBJ){
+ o->flags&=~DREFOBJ;
+ load_reg(f,r,o,POINTER);
+ o->flags|=DREFOBJ;
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ if(!reg_pair(r,&rp)) ierror(0);
+ emit(f,"\tlda\t#>%s\n",mregnames[o->reg]);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tlda\t#<%s\n",mregnames[o->reg]);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ }else if(o->flags&VAR){
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+ load_laddr(f,r,o);
+ }else{
+ o->flags|=VARADR;
+ load_reg(f,r,o,POINTER);
+ o->flags&=~VARADR;
+ }
+ }else if((o->flags&(KONST|DREFOBJ))==KONST){
+ int l=addfpconst(o,t);
+ if(!ieee) ierror(0);
+ if(!reg_pair(r,&rp)) ierror(0);
+ emit(f,"\tlda\t#>%s%d\n",labprefix,l);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tlda\t#<%s%d\n",labprefix,l);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ }else
+ ierror(0);
+}
+
+
+/* Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+
+static void incmem(FILE *f,obj *o,int t,int op,int x)
+{
+ int i,idx=0;
+ char *s;
+ if(ce02&&ISSHORT(t)){
+ if(((o->flags&(REG|DREFOBJ))==REG&&(op==ADD||op==SUB))||
+ (op==LSHIFT&&!indirect(o)&&!o->am)){
+ do{
+ emit(f,"\t%s\t%s\n",op==ADD?"inw":(op==SUB?"dew":"asw"),mregnames[o->reg]);
+ }while(--x);
+ return;
+ }
+ }
+ if((o->flags&(REG|DREFOBJ))==REG&&ISIDX(o->reg)){
+ static char buf[4]=" ";
+ idx=1;s=buf;
+ if(op==ADD){s[0]='i';s[1]='n';}else{s[0]='d';s[1]='e';}
+ s[2]=mregnames[o->reg][0];
+ }else if(op==ADD)
+ s="inc";
+ else if(op==SUB)
+ s="dec";
+ else if(op==LSHIFT)
+ s="asl";
+ else if(op==RSHIFT&&(t&UNSIGNED))
+ s="lsr";
+ else if(op==RSHIFT){
+ s="cmp\t#128\n\tror";
+ }else
+ ierror(0);
+ if(ISCHAR(t)){
+ for(i=0;i<x;i++){
+ if(idx){
+ emit(f,"\t%s\n",s);
+ }else{
+ emit(f,"\t%s\t",s);
+ emit_obj(f,o,t);
+ emit(f,"\n");
+ }
+ }
+ }else{
+ for(i=0;i<x;i++){
+ if(op==SUB){
+ if(m65&&ISLONG(t)){
+ emit(f,"\tdeq\t");
+ emit_obj(f,o,t);
+ emit(f,"\n");
+ }else if(ce02&&iszpage(o)){
+ emit(f,"\tdew\n");
+ }else{
+ /* caller mus make sure accu is available */
+ load_lobyte(f,o,t);
+ emit(f,"\tbne\t%s%d\n",labprefix,++label);
+ emit(f,"\tdec\t");
+ emit_hibyte(f,o,t);
+ emit(f,"\n");
+ if(ISLONG(t)){
+ ierror(0);
+ }
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tdec\t");
+ emit_lobyte(f,o,t);
+ emit(f,"\n");
+ }
+ }else if(op==ADD){
+ if(!optspeed&&m65&&ISLONG(t)){
+ emit(f,"\tinq\t");
+ emit_obj(f,o,t);
+ emit(f,"\n");
+ }else if(!optspeed&&ce02&&iszpage(o)){
+ emit(f,"\tinw\t");
+ emit_lobyte(f,o,t);
+ emit(f,"\n");
+ if(ISLONG(t)){
+ emit(f,"\tbne\t%s%d\n",labprefix,++label);
+ emit(f,"\tinw\t");
+ emit_byte3(f,o,t);
+ emit(f,"\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }else{
+ emit(f,"\t%s\t",s);
+ emit_lobyte(f,o,t);
+ emit(f,"\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,++label);
+ emit(f,"\t%s\t",s);
+ emit_hibyte(f,o,t);
+ emit(f,"\n");
+ if(ISLONG(t)){
+ emit(f,"\tbne\t%s%d\n",labprefix,label);
+ emit(f,"\t%s\t",s);
+ emit_byte3(f,o,t);
+ emit(f,"\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,label);
+ emit(f,"\t%s\t",s);
+ emit_byte4(f,o,t);
+ emit(f,"\n");
+ }
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }else if(op==LSHIFT){
+ if(ce02&&!indirect(o)&&!o->am){
+ emit(f,"\tasw\t");
+ emit_obj(f,o,t);
+ emit(f,"\n");
+ }else{
+ emit(f,"\tasl\t");
+ emit_lobyte(f,o,t);
+ emit(f,"\n");
+ emit(f,"\trol\t");
+ emit_hibyte(f,o,t);
+ emit(f,"\n");
+ }
+ if(ISLONG(t)){
+ do_byte3(f,"rol",o,t);
+ do_byte4(f,"rol",o,t);
+ }
+ }else if(op==RSHIFT&&(t&UNSIGNED)){
+ /*emit(f,"\tclc\n");
+ emit(f,"\tror\t");*/
+ if(ISLONG(t)){
+ do_byte4(f,"lsr",o,t);
+ do_byte3(f,"ror",o,t);
+ do_hibyte(f,"ror",o,t);
+ }else
+ do_hibyte(f,"lsr",o,t);
+ do_lobyte(f,"ror",o,t);
+ }else if(op==RSHIFT){
+ if(ce02){
+ emit(f,"\tasr\t");
+ }else{
+ if(ISLONG(t))
+ do_byte4(f,"lda",o,t);
+ else
+ load_hibyte(f,o,t);
+ emit(f,"\tcmp\t#128\n");
+ emit(f,"\tror\t");
+ }
+ if(ISLONG(t))
+ emit_byte4(f,o,t);
+ else
+ emit_hibyte(f,o,t);
+ emit(f,"\n");
+ if(ISLONG(t)){
+ do_byte3(f,"ror",o,t);
+ do_hibyte(f,"ror",o,t);
+ }
+ do_lobyte(f,"ror",o,t);
+ }else{
+ printf("op=%d\n",op);
+ ierror(0);
+ }
+ }
+ }
+}
+
+static void preload_obj(FILE *f,IC *p,obj *o)
+{
+ int r,pa=0,px=0,longm65=0;long of;
+
+ if((p->typf&VOLATILE)||(p->typf2&VOLATILE)||
+ ((p->q1.flags&DREFOBJ)&&(p->q1.dtyp&(VOLATILE|PVOLATILE)))||
+ ((p->q2.flags&DREFOBJ)&&(p->q2.dtyp&(VOLATILE|PVOLATILE)))||
+ ((p->z.flags&DREFOBJ)&&(p->z.dtyp&(VOLATILE|PVOLATILE))))
+ emit(f,"; volatile barrier\n");
+
+
+ if(m65){
+ int t;
+ if(o==&p->q1)
+ t=q1typ(p);
+ else{
+ if(o==&p->q2) t=q2typ(p);
+ else if(o==&p->z) t=ztyp(p);
+ else ierror(0);
+ if(ISLONG(t)&&LONGM65(p->code)) longm65=1;
+ }
+ }
+
+ if((o->flags&(VAR|REG))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)&&(((of=real_offset(o))+zm2l(szof(o->v->vtyp))>255)||longm65)){
+ r=get_reg(f,p,POINTER);
+ if(o->flags&DREFOBJ){
+ if(p->code==GETRETURN&&(p->q1.reg==ra||p->q1.reg==rax)){
+ emit(f,"\tsta\t%s\n",mregnames[t1]);
+ emit(f,"\tstx\t%s\n",mregnames[t2]);
+ pa=px=1;
+ }else
+ get_acc(f,p,INT);
+ }else{
+ if(p->code==GETRETURN&&(p->q1.reg==ra||p->q1.reg==rax)){
+ emit(f,"\tsta\t%s\n",mregnames[t1]);
+ pa=1;
+ }else
+ cmp_get_acc(f,p,0);
+ }
+ if(!reg_pair(r,&rp)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[fp1]);
+ emit(f,"\tclc\n");
+ if(of&0xff)
+ emit(f,"\tadc\t#%ld\n",of&0xff);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[fp2]);
+ if(1/*of&0xff00*/)
+ emit(f,"\tadc\t#%ld\n",(of>>8)&0xff);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ o->flags|=REG;
+ o->reg=r;
+ if(o->flags&DREFOBJ){
+ if(!zzero) sety(f,0);
+ emit(f,"\tlda\t(%s)%s\n",mregnames[r],zzero?"":",y");
+ emit(f,"\ttxa\n");
+ sety(f,1);
+ emit(f,"\tlda\t(%s),y\n",mregnames[r]);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tstx\t%s\n",mregnames[rp.r1]);
+ }else{
+ o->flags|=DREFOBJ;
+ o->dtyp=POINTER;
+ }
+ if(pa){ emit(f,"\tlda\t%s\n",mregnames[t1]); pa=0;}
+ if(px){ emit(f,"\tldx\t%s\n",mregnames[t2]); px=0;}
+ }
+
+ if((o->flags&(DREFOBJ|KONST))==DREFOBJ&&(!(o->flags®)||!isptr(o->reg))&&(!(o->flags&VAR)||!(o->v->tattr&ZPAGE))&&!ISFPOINTER(o->dtyp)){
+ if(p->code==GETRETURN&&(p->q1.reg==ra||p->q1.reg==rax)){
+ emit(f,"\tsta\t%s\n",mregnames[t1]);
+ pa=1;
+ }else
+ cmp_get_acc(f,p,0);
+ r=get_reg(f,p,POINTER);
+ o->flags&=~DREFOBJ;
+ load_reg(f,r,o,POINTER);
+ o->flags|=REG|DREFOBJ;
+ o->reg=r;
+ if(pa){ emit(f,"\tlda\t%s\n",mregnames[t1]); pa=0;}
+ }
+}
+
+static void far_copy(FILE *f,IC *p)
+{
+ int b;long l;
+ get_acc(f,p,INT);
+ if(p->code==PUSH){
+ if(!reg_pair(LAST_PAIR,&rp)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ if(pushed) emit(f,"\tclc\n");
+ if(pushed&0xff) emit(f,"\tadc\t#%d\n",(pushed&0xff));
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+ if(pushed) emit(f,"\tadc\t#%d\n",((pushed>>8)&0xff));
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ pushed+=zm2l(p->q2.val.vmax);
+ emit(f,"\tldx\t#%d\n",bankcnum);
+ }else if(p->z.flags&DREFOBJ){
+ if(!reg_pair(LAST_PAIR,&rp)) ierror(0);
+ p->z.flags&=~DREFOBJ;
+ load_lobyte(f,&p->z,FPOINTER);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ load_hibyte(f,&p->z,FPOINTER);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ if(indirect(&p->z)){
+ do_byte3(f,"lda",&p->z,FPOINTER);
+ emit(f,"\ttax\n");
+ }else
+ do_byte3(f,"ldx",&p->z,FPOINTER);
+ }else{
+ load_address(f,LAST_PAIR,&p->z,POINTER);
+ b=bank(p->z.v);
+ emit(f,"\tldx\t#%d\n",b>=0?b:bankcnum);
+ }
+ if(p->q1.flags&DREFOBJ){
+ if(!reg_pair(LAST_PAIR-1,&rp)) ierror(0);
+ p->q1.flags&=~DREFOBJ;
+ load_lobyte(f,&p->q1,FPOINTER);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ load_hibyte(f,&p->q1,FPOINTER);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ if(indirect(&p->q1)){
+ do_byte3(f,"lda",&p->q1,FPOINTER);
+ emit(f,"\ttay\n");
+ }else
+ do_byte3(f,"ldy",&p->q1,FPOINTER);
+ }else{
+ load_address(f,LAST_PAIR-1,&p->q1,POINTER);
+ b=bank(p->q1.v);
+ sety(f,b>=0?b:bankcnum);
+ }
+ l=zm2l(p->q2.val.vmax);
+ emit(f,"\tlda\t#%d\n",(l>>8)&0xff);
+ emit(f,"\tsta\t%s__bankcopy_len+1\n",idprefix);
+ emit(f,"\tlda\t#%d\n",(l)&0xff);
+ emit(f,"\tsta\t%s__bankcopy_len\n",idprefix);
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ emit(f,"\tjsr\t%s__bankcopy\n",idprefix);
+ yval=NOVAL;
+}
+
+static void load_far(FILE *f,IC *p,obj *o,int t)
+{
+ int pushed=0;
+ if(!(o->flags&DREFOBJ)) ierror(0);
+ o->flags&=~DREFOBJ;
+ t&=NQ;
+ if(zmeqto(sizetab[t],Z0)) return;
+ /*get_acc(f,p,INT);*/
+ if(pushedacc==t3||pushedacc==t4) ierror(0);
+ if(pushedx==t3||pushedx==t4) ierror(0);
+ if(regs[ra]||regs[rax]){
+ if(isacc(q1)||isacc(q2)||!isacc(z)){
+ pushed=1;
+ emit(f,"\tpha\n");
+ if(regs[rax]) emit(f,"\ttxa\n\tpha\n");
+ }
+ }
+ load_reg(f,LAST_PAIR,o,POINTER);
+ if(!indirect(o))
+ do_byte3(f,"ldy",o,CHAR);
+ else{
+ do_byte3(f,"lda",o,CHAR);
+ emit(f,"\ttay\n");
+ }
+ emit(f,"\tldx\t#%d\n",bankvoffset);
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ emit(f,"\tjsr\t%s__bankload%d\n",idprefix,(int)zm2l(sizetab[t]));
+ yval=NOVAL;
+ o->flags=VAR;
+ o->v=&bankv;
+ o->val.vmax=l2zm((long)bankvoffset);
+ bankvoffset+=zm2l(sizetab[t]);
+ if(pushed){
+ if(regs[rax]) emit(f,"\tpla\n\ttax\n");
+ emit(f,"\tpla\n");
+ }
+}
+
+static void load_banked(FILE *f,IC *p,obj *o,int t)
+{
+ int pushed=0,m;
+ if(o->flags&DREFOBJ) t=o->dtyp;
+ t&=NQ;
+ if(zmeqto(sizetab[t],Z0)) return;
+ /*get_acc(f,p,INT);*/
+ if(pushedacc==t3||pushedacc==t4) ierror(0);
+ if(pushedx==t3||pushedx==t4) ierror(0);
+ if(regs[ra]||regs[rax]){
+ if(isacc(q1)||isacc(q2)||!isacc(z)){
+ pushed=1;
+ emit(f,"\tpha\n");
+ if(regs[rax]||regs[rx]) emit(f,"\ttxa\n\tpha\n");
+ }
+ }
+ m=o->flags;
+ o->flags&=~DREFOBJ;
+ load_address(f,LAST_PAIR,o,POINTER);
+ o->flags=m;
+ emit(f,"\tldx\t#%d\n",bankvoffset);
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ sety(f,bank(o->v));
+ emit(f,"\tjsr\t%s__bankload%d\n",idprefix,(int)zm2l(sizetab[t]));
+ yval=NOVAL;
+ o->v=&bankv;
+ o->val.vmax=l2zm((long)bankvoffset);
+ bankvoffset+=zm2l(sizetab[t]);
+ if(pushed){
+ if(regs[rax]||regs[rx]) emit(f,"\tpla\n\ttax\n");
+ emit(f,"\tpla\n");
+ }
+}
+
+static void preload(FILE *f,IC *p)
+{
+ int r,mra=regs[ra],mrax=regs[rax];
+ int bq1=-1,bq2=-1,bz=-1,sb=-1,zbuf=0;
+
+ if(((p->q1.flags&DREFOBJ)&&p->q1.am&&(p->q1.am->flags==GPR_IND||p->q1.am->flags==ABS_IND)&&p->q1.am->idx==ra)||
+ ((p->q2.flags&DREFOBJ)&&p->q2.am&&(p->q2.am->flags==GPR_IND||p->q2.am->flags==ABS_IND)&&p->q2.am->idx==ra)||
+ ((p->z.flags&DREFOBJ)&&p->z.am&&(p->z.am->flags==GPR_IND||p->z.am->flags==ABS_IND)&&p->z.am->idx==ra)
+ ){
+ if(pushedacc>0)
+ r=pushedacc;
+ else{
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ }
+ pushedacc=r;
+ if((p->q1.flags&DREFOBJ)&&p->q1.am&&(p->q1.am->flags==GPR_IND||p->q1.am->flags==ABS_IND)&&p->q1.am->idx==ra)
+ p->q1.am->idx=r;
+ if((p->q2.flags&DREFOBJ)&&p->q2.am&&(p->q2.am->flags==GPR_IND||p->q2.am->flags==ABS_IND)&&p->q2.am->idx==ra)
+ p->q2.am->idx=r;
+ if((p->z.flags&DREFOBJ)&&p->z.am&&(p->z.am->flags==GPR_IND||p->z.am->flags==ABS_IND)&&p->z.am->idx==ra)
+ p->z.am->idx=r;
+ }
+
+ if(p->code==GETRETURN&&p->q1.reg==ra&&!regs[ra])
+ regs[ra]=1;
+
+ if(p->code==GETRETURN&&p->q1.reg==rax&&!regs[rax])
+ regs[rax]=1;
+
+ bankvoffset=0;
+
+ if(!NOBANKVARS){
+ if((p->q1.flags&(VAR|VARADR))==VAR) bq1=bank(p->q1.v);
+ if((p->q2.flags&(VAR|VARADR))==VAR) bq2=bank(p->q2.v);
+ if((p->z.flags&(VAR|VARADR))==VAR) bz=bank(p->z.v);
+
+ if((p->q1.flags&(VAR|VARADR))==(VAR|VARADR)){
+ r=bank(p->q1.v);
+ /*if(r>=0&&r!=cbank) ierror(0);*/
+ }
+
+ if((p->code==ASSIGN||p->code==PUSH)&&!zmleq(p->q2.val.vmax,l2zm(4L))){
+ if(p->q1.flags&DREFOBJ) preload_obj(f,p,&p->q1);
+ if(p->z.flags&DREFOBJ) preload_obj(f,p,&p->z);
+ return;
+ }
+
+ if(p->code!=CALL){
+ /* TODO: some optimizations possible */
+ if(bq1>=0&&bq1!=cbank){
+ if(cbank<0&&!NOSWITCH)
+ sb=bq1;
+ else
+ load_banked(f,p,&p->q1,q1typ(p));
+ }
+ if(bq2>=0&&bq2!=cbank){
+ if((bq2==sb||(cbank<0&&sb<0))&&!NOSWITCH)
+ sb=bq2;
+ else
+ load_banked(f,p,&p->q2,q2typ(p));
+ }
+ if(bz>=0&&bz!=cbank&&(p->z.flags&DREFOBJ)){
+ if((bz==sb||(cbank<0&&sb<0))||!NOSWITCH)
+ sb=bz;
+ else
+ load_banked(f,p,&p->z,ztyp(p));
+ }
+
+ if(sb>=0){
+ if(NOSWITCH) ierror(0);
+ sety(f,sb);
+ emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+ yval=NOVAL;
+ }
+ }
+ }
+
+ if((p->q1.flags&DREFOBJ)&&ISFPOINTER(p->q1.dtyp)&&p->code!=CALL) load_far(f,p,&p->q1,q1typ(p));
+ if((p->q2.flags&DREFOBJ)&&ISFPOINTER(p->q2.dtyp)) load_far(f,p,&p->q2,q2typ(p));
+
+ if(isacc(q2)){
+ static obj o;
+ int t=q2typ(p);
+ r=get_reg(f,p,t);
+ o.flags=REG;
+ o.reg=r;
+ store_acc(f,&o,t);
+ p->q2.reg=r;
+ if(!pushedacc){
+ if((t&NQ)==CHAR)
+ storedacc=r;
+ else{
+ if(!reg_pair(r,&rp)) ierror(0);
+ storedacc=rp.r1;
+ storedx=rp.r2;
+ }
+ }
+ }
+
+ if((p->code==ADDI2P||p->code==SUBIFP)&&ISRIDX(q2)){
+ static obj o;
+ if(p->q2.reg==rx){
+ if(pushedx>0) r=pushedx;
+ else if(storedx>0) r=storedx;
+ else r=get_reg(f,p,CHAR);
+ }else
+ r=get_reg(f,p,CHAR);
+ o.flags=REG;
+ o.reg=r;
+ store_reg(f,p->q2.reg,&o,CHAR);
+ p->q2.reg=r;
+ storedx=r;
+ }
+
+ if(p->code!=ADDRESS){
+ preload_obj(f,p,&p->q1);
+ if((p->q1.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+ (p->q2.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+ p->q1.v==p->q2.v){
+ p->q2.flags|=REG;
+ p->q2.reg=p->q1.reg;
+ }
+ if((p->q1.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+ (p->z.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+ p->q1.v==p->z.v){
+ p->z.flags|=REG;
+ p->z.reg=p->q1.reg;
+ }
+ }
+
+ preload_obj(f,p,&p->q2);
+ if((p->q2.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+ (p->z.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+ p->q2.v==p->z.v){
+ p->z.flags|=REG;
+ p->z.reg=p->q2.reg;
+ }
+
+
+ if((p->z.flags&DREFOBJ)&&ISFPOINTER(p->z.dtyp)) zbuf=1;
+ if((p->z.flags&(VAR|DREFOBJ))==VAR){
+ bz=bank(p->z.v);
+ if(bz>=0&&bz!=cbank) zbuf=1;
+ }
+
+ if(zbuf&&!NOBANKVARS){
+ zstore=p->z;
+ p->z.flags=VAR;
+ p->z.v=&bankv;
+ p->z.val.vmax=l2zm((long)bankvoffset);
+ zstoreflag=1;
+ /*bankvoffset+=zm2l(sizetab[p->typf&NQ]);*/
+ }else{
+ preload_obj(f,p,&p->z);
+
+ if(isreg(z)){
+ r=0;
+ if(p->q1.am&&p->q1.am->base==p->z.reg){
+ r=get_reg(f,p,POINTER);
+ cmp_get_acc(f,p,0);
+ if(!reg_pair(p->q1.am->base,&rp)) ierror(0);
+ if(!reg_pair(r,&rp2)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+ p->q1.am->base=p->q1.reg=r;
+ }else if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q1.reg==p->z.reg){
+ r=get_reg(f,p,POINTER);
+ cmp_get_acc(f,p,0);
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ if(!reg_pair(r,&rp2)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+ p->q1.reg=r;
+ }
+ if(p->q2.am&&p->q2.am->base==p->z.reg){
+ if(r==0){
+ r=get_reg(f,p,POINTER);
+ cmp_get_acc(f,p,0);
+ if(!reg_pair(p->q2.am->base,&rp)) ierror(0);
+ if(!reg_pair(r,&rp2)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+ }
+ p->q2.am->base=p->q2.reg=r;
+ }else if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg==p->z.reg){
+ if(r==0){
+ r=get_reg(f,p,POINTER);
+ cmp_get_acc(f,p,0);
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ if(!reg_pair(r,&rp2)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+ }
+ p->q2.reg=r;
+ }
+ }
+ if(isacc(z)){
+ if(isacc(q2)){
+ if(p->q2.reg==rax){
+ r=get_reg(f,p,INT);
+ if(!reg_pair(r,&rp)) ierror(0);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tstx\t%s\n",mregnames[rp.r2]);
+ storedacc=rp.r1;
+ storedx=rp.r2;
+ }else{
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ storedacc=r;
+ }
+ p->q2.reg=r;
+ if(isacc(q1))
+ p->q1.reg=r;
+ }
+ }
+ }
+
+ reload_acc(f);
+
+ regs[ra]=mra;
+ regs[rax]=mrax;
+}
+
+
+/* compare if two objects are the same */
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+ if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
+ return 1;
+ if(o1->flags==o2->flags){
+ if(o1->am){
+ if(o2->am){
+ if(o1->am->flags!=o2->am->flags||o1->am->base!=o2->am->base||
+ o1->am->idx!=o2->am->idx||o1->am->offset!=o2->am->offset)
+ return 0;
+ else
+ return 1;
+ }else
+ return 0;
+ }else if(o2->am)
+ return 0;
+ if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+ if(!(o1->flags®)||o1->reg==o2->reg){
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+ ierror(0);
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+ if(p->am){
+ if(p->am->flags==IMM_IND)
+ emit(f,"(%s),y ;am(%ld)",mregnames[p->am->base],p->am->offset);
+ else if(p->am->flags==GPR_IND)
+ emit(f,"(%s),y ;am(%s)",mregnames[p->am->base],mregnames[p->am->idx]);
+ else if(p->am->flags==ABS_IND){
+ emit(f,"%ld",p->am->offset);
+ if(p->am->v){
+ Var *v=p->am->v;
+ if(v->storage_class==EXTERN)
+ emit(f,"+%s%s",idprefix,v->identifier);
+ else
+ emit(f,"+%s%ld",labprefix,zm2l(v->offset));
+ }
+ if(ISIDX(p->am->idx))
+ emit(f,",%s ;am(%s)",mregnames[p->am->idx],mregnames[p->am->idx]);
+ else
+ emit(f,",y ;am(%s)",mregnames[p->am->idx]);
+ }else
+ ierror(0);
+ return;
+ }
+ if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if(p->flags&DREFOBJ) emit(f,"(");
+ if(p->flags®){
+ emit(f,"%s",mregnames[p->reg]);
+ }else if(p->flags&VAR) {
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+ emit(f,"(%s),%s",mregnames[fp],noy==2?"z":"y");
+ else{
+ if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,MAXINT);emit(f,"+");}
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ }
+ }
+ if(p->flags&KONST){
+ if(/*ieee&&((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)*/ISFLOAT(t))
+ emit(f,"%s%d",labprefix,addfpconst(p,t));
+ else
+ emitval(f,&p->val,t&NU);
+ }
+ if(p->flags&DREFOBJ) emit(f,")%s",noy==0?",y":(noy==1?"":",z"));
+}
+
+/* Test if there is a sequence of FREEREGs containing FREEREG reg.
+ Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+ while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+ if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+ p=p->next;
+ }
+ return 0;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+ int c,c2,r;struct IC *p2,*free_base,*use;struct AddressingMode *am;
+
+ for(;p;p=p->next){
+ c=p->code;
+ if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+ if(c==LABEL) exit_label=p->typf;
+
+ /* Try const(reg) */
+ if((c==ADDI2P||c==SUBIFP)&&ISPREG(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&!ISFPOINTER(p->typf2)){
+ int base;zmax of;struct obj *o;IC *dub=0;
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ if(zmleq(Z0,of)&&zmleq(of,l2zm(255L))){
+ r=p->z.reg;
+ if(isreg(q1)&&isptr(p->q1.reg)) base=p->q1.reg; else base=r;
+ o=0;free_base=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2==FREEREG&&p2->q1.reg==p->z.reg) free_base=p2;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ int t,mc;
+ if((c2==ASSIGN|c2==PUSH)&&(p2->typf&NQ)==CHAR&&!zmeqto(p2->q2.val.vmax,Z1))
+ mc=1;
+ else
+ mc=0;
+ if(!o&&(c2==ADD||c2==SUB||c2==AND||c2==OR||c2==XOR)&&/*(p2->typf&NQ)==CHAR&&*/!p2->q1.am&&!p2->z.am&&
+ (p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&
+ p2->q1.flags==p2->z.flags&&p2->q1.reg==r&&p2->z.reg==r){
+ o=&p2->q1;use=p2;
+ dub=p2;
+ continue;
+ }
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||mc) break;
+ t=q1typ(p2)&NQ;
+ if(t>POINTER||ISFLOAT(t)) break;
+ if(m65&&ISLONG(t)) break;
+ o=&p2->q1;use=p2;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||mc) break;
+ t=q2typ(p2)&NQ;
+ if(t>POINTER||ISFLOAT(t)) break;
+ if(m65&&ISLONG(t)) break;
+ o=&p2->q2;use=p2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||mc) break;
+ t=ztyp(p2)&NQ;
+ if(t>POINTER||ISFLOAT(t)) break;
+ if(m65&&ISLONG(t)) break;
+ o=&p2->z;use=p2;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else{
+ m=p2->z.reg;
+ if(o==&p->q1||o==&p->q2) break;
+ }
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ am->base=base;
+ am->offset=(int)zm2l(of);
+ if(ISPREG(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ if(dub){
+ dub->z=*o;
+ dub->z.am=mymalloc(sizeof(*am));
+ *dub->z.am=*o->am;
+ }
+ if(free_base) move_IC(use,free_base);
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+ /* Try reg,reg */
+ if(c==ADDI2P&&(p->typf&NU)==(UNSIGNED|CHAR)&&!ISFPOINTER(p->typf2)&&isreg(q2)/*&&p->q2.reg!=ra*/&&ISPREG(z)&&(ISPREG(q1)||p->q2.reg!=p->z.reg)){
+ int base,idx,ind;struct obj *o;IC *free_idx,*dub=0;
+ r=p->z.reg;idx=p->q2.reg;
+ if(ISPREG(q1)) base=p->q1.reg; else base=r;
+ if((p->q1.flags&VARADR)||(p->q1.flags&(KONST|DREFOBJ))==KONST)
+ ind=0;
+ else
+ ind=1;
+ o=0;free_base=free_idx=use=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2==FREEREG&&p2->q1.reg==p->z.reg) free_base=p2;
+ if(c2==FREEREG&&p2->q1.reg==p->q2.reg) free_idx=p2;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if((p2->z.flags&(REG|DREFOBJ))==REG&&idx!=r){
+ if(p2->z.reg==idx) break;
+ if(reg_pair(p2->z.reg,&rp)){
+ if(rp.r1==idx) break;
+ if(rp.r2==idx) break;
+ }
+ }
+
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!o&&(c2==ADD||c2==SUB||c2==AND||c2==OR||c2==XOR)&&/*(p2->typf&NQ)==CHAR&&*/!p2->q1.am&&!p2->z.am&&
+ (p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&
+ p2->q1.flags==p2->z.flags&&p2->q1.reg==r&&p2->z.reg==r){
+ o=&p2->q1;use=p2;
+ dub=p2;
+ continue;
+ }
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||(ind&&(q1typ(p2)&NQ)!=CHAR)) break;
+ if(ieee&&ISFLOAT(q1typ(p2))) break;
+ o=&p2->q1;use=p2;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||(ind&&(q2typ(p2)&NQ)!=CHAR)) break;
+ if(ieee&&ISFLOAT(q2typ(p2))) break;
+ o=&p2->q2;use=p2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||(ind&&(ztyp(p2)&NQ)!=CHAR)) break;
+ if(ieee&&ISFLOAT(ztyp(p2))) break;
+ o=&p2->z;use=p2;
+ }
+ }
+
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->idx=idx;
+ if(ind){
+ am->flags=GPR_IND;
+ am->base=base;
+ if(ISPREG(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }else{
+ am->flags=ABS_IND;
+ am->base=0;
+ eval_const(&p->q1.val,MAXINT);
+ am->offset=zm2l(vmax);
+ if(p->q1.flags&VARADR)
+ am->v=p->q1.v;
+ else
+ am->v=0;
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }
+ if(dub){
+ dub->z=*o;
+ dub->z.am=mymalloc(sizeof(*am));
+ *dub->z.am=*o->am;
+ }
+ if(free_idx) move_IC(use,free_idx);
+ if(free_base) move_IC(use,free_base);
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+}
+
+static void pr(FILE *f,struct IC *p)
+{
+ int r;
+
+ if(zstoreflag){
+ int off;
+ if(p->z.flags!=VAR||p->z.v!=&bankv) ierror(0);
+ off=(int)zm2l(p->z.val.vmax);
+ p->z=zstore;
+ get_acc(f,p,INT);
+ if(zstore.flags&DREFOBJ){
+ if(!ISFPOINTER(zstore.dtyp)) ierror(0);
+ zstore.flags&=~DREFOBJ;
+ load_reg(f,LAST_PAIR,&zstore,POINTER);
+ if(indirect(&zstore)){
+ do_byte3(f,"lda",&zstore,FPOINTER);
+ emit(f,"\ttay\n");
+ }else
+ do_byte3(f,"ldy",&zstore,FPOINTER);
+ yval=NOVAL;
+ }else{
+ load_address(f,LAST_PAIR,&zstore,p->typf);
+ r=bank(zstore.v);
+ sety(f,r>=0?r:bankcnum);
+ }
+ emit(f,"\tldx\t#%d\n",off);
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ emit(f,"\tjsr\t%s__bankstore%d\n",idprefix,(int)zm2l(sizetab[p->typf&NQ]));
+ yval=NOVAL;
+ zstoreflag=0;
+ }
+
+ for(r=1;r<=MAXR;r++){
+ if(regs[r]&8)
+ regs[r]&=~8;
+ }
+ for(r=FIRST_GPR;r<=LAST_GPR;r++){
+ int ta=0;
+ if(regs[r]&2){
+ if(regs[ra]&&!pushedacc){
+ emit(f,"\ttay\n");
+ yval=NOVAL;
+ ta=1;
+ }
+ emit(f,"\tpla\n");
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ regs[r]&=~2;
+ }
+ if(ta)
+ emit(f,"\ttya\n");
+ }
+ if(pushedx){
+ emit(f,"\tldx\t%s\n",mregnames[pushedx]);
+ pushedx=0;
+ }
+
+ reload_acc_opt(f,p->next);
+
+ storedacc=0;
+ storedx=0;
+}
+
+struct cmplist {struct cmplist *next;int from,to,mode;} *first_cmplist;
+
+static void add_cmplist(int from, int to, int mode)
+{
+ struct cmplist *new;
+ new=mymalloc(sizeof(*new));
+ new->next=first_cmplist;
+ new->from=from;
+ new->to=to;
+ new->mode=mode;
+ first_cmplist=new;
+}
+
+static void incsp(FILE *f,long of)
+{
+ if(of==0) return;
+ if(of==1||of==-1){
+ static obj o;
+ o.flags=REG;
+ o.reg=sp;
+ if(of==1)
+ incmem(f,&o,INT,ADD,1);
+ else
+ incmem(f,&o,INT,SUB,1);
+ }else if(of==256){
+ emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+ }else if(of==-256){
+ emit(f,"\tdec\t%s+1\n",mregnames[sp]);
+ }else{
+ long abs;
+ if(of>0){
+ abs=of;
+ emit(f,"\tclc\n");
+ }else{
+ abs=-of;
+ emit(f,"\tsec\n");
+ }
+ if(abs&255){
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ if(of>0){
+ emit(f,"\tadc\t#%ld\n",abs&255);
+ }else{
+ emit(f,"\tsbc\t#%ld\n",abs&255);
+ }
+ emit(f,"\tsta\t%s\n",mregnames[sp]);
+ }
+ if((abs&0xff00)==0){
+ if(of>0){
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+ emit(f,"%s%d:\n",labprefix,label);
+ }else{
+ emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+ emit(f,"\tdec\t%s+1\n",mregnames[sp]);
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }else{
+ emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+ if(of>0)
+ emit(f,"\tadc\t#%ld\n",(abs>>8)&255);
+ else
+ emit(f,"\tsbc\t#%ld\n",(abs>>8)&255);
+ emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+ }
+ }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+ int i,r,of;
+ rsavesize=0;
+ libsave=1;
+ hasretval=0;
+
+ if(!optsize||(v->tattr&NOCOMPRESS)) emit(f,";vcprmin=10000\n");
+ if(vlas) emit(f,"___fo\tset\t%ld\n",(long)argsize);
+ r=0;
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&®scratch[i]&&!regsa[i])){
+ if(i!=LAST_GPR-VOL_GPRS+1&&r==0) libsave=0;
+ rsavesize++;
+ r=1;
+ }else{
+ if(i==LAST_GPR-VOL_GPRS+1) libsave=0;
+ r=0;
+ }
+ }
+ rscnt=rsavesize;
+ if(rscnt&&!SOFTSTACK){
+ if(optspeed||rscnt<2)
+ rsavesize=0;
+ else if(!optsize&&rscnt<=5)
+ rsavesize=0;
+ }
+
+ if(!special_section(f,v)){emit(f,codename);ebank(f,sbank(v));if(f) section=CODE;}
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\tglobal\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+
+ offset=localsize+argsize+rsavesize;
+
+ if(in_isr){
+ emit(f,"\tpha\n");
+ if(c02){
+ emit(f,"\tphx\n");
+ emit(f,"\tphy\n");
+ }else{
+ emit(f,"\ttxa\n");
+ emit(f,"\tpha\n");
+ emit(f,"\ttya\n");
+ emit(f,"\tpha\n");
+ }
+ if(offset||function_calls){
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ emit(f,"\tpha\n");
+ emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+ emit(f,"\tpha\n");
+ emit(f,"\tlda\t#<(___isrstack-%ld)\n",offset);
+ emit(f,"\tsta\t%s\n",mregnames[sp]);
+ emit(f,"\tlda\t#>(___isrstack-%ld)\n",offset);
+ emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+ }
+ }
+
+ if(MAINARGS&&v->storage_class==EXTERN&&!strcmp(v->identifier,"main")&&v->vtyp->exact->count>1)
+ emit(f,"\tjsr\tinitmainargs\n");
+
+ yval=NOVAL;
+ of=argsize+localsize;
+
+ if(rsavesize>0&&of+rsavesize>255){
+ offset-=rsavesize;
+ incsp(f,-rsavesize);
+ of=0;
+ }else{
+ incsp(f,-offset);
+ offset=0;
+ }
+
+
+ if(!libsave||rscnt!=rsavesize||optspeed||rscnt<=1||(rscnt<=3&&(!optsize)))
+ libsave=0;
+
+ if(libsave){
+ sety(f,of+rsavesize-1);
+ if(0/*mask_opt*/)
+ emit(f,"\tjsr\t%s__rsave.%d+%ld\n",idprefix,(1<<(rscnt-2)),(rscnt-2)*5);
+ else
+ emit(f,"\tjsr\t%s__rsave%ld\n",idprefix,rscnt);
+ yval=of;
+ }else{
+ int last=0;
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&®scratch[i]&&!regsa[i])){
+ if(rscnt!=rsavesize){
+ if(ce02&&last==i-1){
+ emit(f,"\tphw\t%s\n",mregnames[last]);
+ last=0;
+ }else{
+ if(!ce02){
+ emit(f,"\tlda\t%s\n",mregnames[i]);
+ emit(f,"\tpha\n");
+ }else
+ last=i;
+ }
+ }else{
+ sety(f,of++);
+ emit(f,"\tlda\t%s\n",mregnames[i]);
+ emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+ }
+ }
+ }
+ if(last){
+ emit(f,"\tlda\t%s\n",mregnames[last]);
+ emit(f,"\tpha\n");
+ }
+ }
+
+
+
+ incsp(f,-offset);
+
+ if(vlas){
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ emit(f,"\tsta\t%s\n",mregnames[fp]);
+ emit(f,"\tlda\t%s\n",mregnames[sp2]);
+ emit(f,"\tsta\t%s\n",mregnames[fp2]);
+ }
+}
+
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+ int i,of,ar;
+ struct cmplist *p;
+ offset=localsize+argsize+rsavesize;
+ of=argsize+localsize;
+
+ i=freturn(v->vtyp->next);
+ if(hasretval&&(i==ra||i==rax)) ar=1; else ar=0;
+
+ if(rscnt!=rsavesize){
+ if(ar&&!pushedacc){
+ pushedacc=t4;
+ emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+ }
+ for(i=LAST_GPR;i>=FIRST_GPR;i--){
+ if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&®scratch[i]&&!regsa[i])){
+ emit(f,"\tpla\n");
+ emit(f,"\tsta\t%s\n",mregnames[i]);
+ }
+ }
+ }
+ if(rsavesize>0&&of+rsavesize>255){
+ if(of!=1&&ar&&!pushedacc){
+ pushedacc=t4;
+ emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+ }
+ incsp(f,of);
+ offset-=of;
+ of=0;
+ }
+ if(rsavesize>0){
+ if(ar&&!pushedacc){
+ pushedacc=t4;
+ emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+ }
+ }
+ if(rsavesize){
+ if(libsave){
+ sety(f,of+rsavesize-1);
+ if(0/*mask_opt*/)
+ emit(f,"\tjsr\t%s__rload.%d+%ld\n",idprefix,(1<<(rscnt-2)),(rscnt-2)*5);
+ else
+ emit(f,"\tjsr\t%s__rload%ld\n",idprefix,rscnt);
+ yval=of;
+ }else{
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&®scratch[i]&&!regsa[i])){
+ sety(f,of++);
+ emit(f,"\tlda\t(%s),y\n",mregnames[sp]);
+ emit(f,"\tsta\t%s\n",mregnames[i]);
+ }
+ }
+ }
+ }
+ if(in_isr){
+ if(offset||function_calls){
+ emit(f,"\tpla\n");
+ emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+ emit(f,"\tpla\n");
+ emit(f,"\tsta\t%s\n",mregnames[sp]);
+ }
+ }else if(offset==2&&!pushedacc){
+ emit(f,"\tinc\t%s\n",mregnames[sp]);
+ emit(f,"\tbeq\t%s%d\n",labprefix,++label);
+ emit(f,"\tinc\t%s\n",mregnames[sp]);
+ emit(f,"\tbeq\t%s%d\n",labprefix,++label);
+ reload_acc(f);
+ emit(f,ret);
+ emit(f,"%s%d:\n",labprefix,label-1);
+ emit(f,"\tinc\t%s\n",mregnames[sp]);
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+ }else{
+ if(offset!=0&&ar&&!pushedacc){
+ pushedacc=t4;
+ emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+ }
+ incsp(f,offset);
+ }
+
+ reload_acc(f);
+
+ if(in_isr){
+ if(c02){
+ emit(f,"\tply\n");
+ emit(f,"\tplx\n");
+ }else{
+ emit(f,"\tpla\n");
+ emit(f,"\ttay\n");
+ emit(f,"\tpla\n");
+ emit(f,"\ttax\n");
+ }
+ emit(f,"\tpla\n");
+ }
+ emit(f,ret);
+
+ for(p=first_cmplist;p;){
+ struct cmplist *m;
+ emit(f,"%s%d:\n",labprefix,p->from);
+ if(p->mode==JMPIND){
+ /* indirect call */
+ emit(f,"\tjmp\t(%s)\n",mregnames[p->to]);
+ }else{
+ pushedacc=p->mode;
+ reload_acc(f);
+ emit(f,"\t%s\t%s%d\n",jmpinst,labprefix,p->to);
+ }
+ m=p;
+ p=p->next;
+ free(m);
+ }
+ first_cmplist=0;
+ pushedacc=0;
+}
+
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+int init_cg(void)
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(1L);
+ char_bit=l2zm(8L);
+ stackalign=l2zm(1);
+
+ if(IEEE){
+ ieee=1;
+ msizetab[DOUBLE]=msizetab[LDOUBLE]=l2zm(8L);
+ }
+
+
+ mregnames[0]=regnames[0]="noreg";
+ mregnames[REGDUMMY1]=mymalloc(MAXI+8);
+ mregnames[REGDUMMY2]=mymalloc(MAXI+8);
+ mregnames[REGDUMMY3]=mymalloc(MAXI+8);
+
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"r%d",i-FIRST_GPR);
+ mregnames[i]=regnames[i];
+ regsize[i]=l2zm(1L);
+ regtype[i]=&ctyp;
+ }
+ for(i=FIRST_PAIR;i<=LAST_PAIR;i++){
+ int sr=(i-FIRST_PAIR)*2+FIRST_GPR;
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"%s/%s",mregnames[sr],mregnames[sr+1]);
+ mregnames[i]=regnames[sr];
+ regsize[i]=l2zm(2L);
+ regtype[i]=&ityp;
+ }
+ for(i=FIRST_BIG;i<=LAST_BIG;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"btmp%d",i-FIRST_BIG);
+ mregnames[i]=regnames[i];
+ regsize[i]=msizetab[FLOAT];
+ regtype[i]=&ftyp;
+ regsa[i]=0;
+ regscratch[i]=1;
+ }
+ for(i=FIRST_BIGP;i<=LAST_BIGP;i++){
+ int sr=(i-FIRST_BIGP)*2+FIRST_BIG;
+ regnames[i]=mymalloc(20);
+ sprintf(regnames[i],"%s/%s",mregnames[sr],mregnames[sr+1]);
+ mregnames[i]=regnames[sr];
+ regsize[i]=msizetab[LLONG];
+ regtype[i]=&lltyp;
+ regsa[i]=0;
+ regscratch[i]=1;
+ }
+
+ mregnames[ra] = regnames[ra] = "a";
+ mregnames[rx] = regnames[rx] = "x";
+ mregnames[ry] = regnames[ry] = "y";
+ regsize[ra]=regsize[rx]=regsize[ry]=l2zm(1L);
+ regtype[ra]=regtype[rx]=regtype[ry]=&ctyp;
+ mregnames[sp]=regnames[sp] = "sp";
+ mregnames[sp1]=regnames[sp1] = "sp";
+ mregnames[sp2]=regnames[sp2] = "sp+1";
+
+ mregnames[rax]=regnames[rax] = "a/x";
+ regsize[rax]=regsize[sp]=l2zm(2L);
+ regtype[rax]=regtype[sp]=&ityp;
+
+ reg_prio[ra]=reg_prio[rax]=100;
+ reg_prio[rx]=50;
+
+ /* Use multiple ccs. */
+ multiple_ccs=0;
+
+ short_push=1;
+
+ static_cse=0;
+
+ dref_cse=1;
+
+ /*prefer_statics=1; TODO */
+
+
+ if(optsize){
+ clist_copy_stack=2;
+ clist_copy_pointer=2;
+ clist_copy_static=2;
+ }else if(optspeed){
+ clist_copy_stack=64;
+ clist_copy_pointer=64;
+ clist_copy_static=64;
+ }else{
+ clist_copy_stack=8;
+ clist_copy_pointer=8;
+ clist_copy_static=8;
+ }
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[INT]=t_min(SHORT);
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[LONG]=ul2zum(2147483647UL);
+ t_max[INT]=t_max(SHORT);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[LONG]=ul2zum(4294967295UL);
+ tu_max[INT]=t_max(UNSIGNED|SHORT);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ /* This is not optimal but simple. */
+ regsa[ry]=regsa[sp]=regsa[sp1]=regsa[sp2]=REGSA_NEVER;
+ regsa[t1]=regsa[t2]=regsa[t3]=regsa[t4]=REGSA_NEVER;
+ regscratch[ra]=regscratch[rx]=regscratch[rax]=1;
+ if(!GLOBACC)
+ regsa[ra]=regsa[rx]=regsa[rax]=REGSA_TEMPS;
+ regsa[rx]=0;
+ regscratch[sp]=regscratch[sp1]=regscratch[sp2]=regscratch[ry]=0;
+ regscratch[t1]=regscratch[t2]=regscratch[t3]=regscratch[t4]=1;
+
+ for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++){
+ regscratch[i]=1;
+ if(i&1)
+ regscratch[FIRST_PAIR+(i-FIRST_GPR)/2]=1;
+ }
+
+ target_macros=marray;
+
+ declare_builtin("__mulint8",CHAR,CHAR,FIRST_GPR,CHAR,FIRST_GPR+1,1,0);
+ declare_builtin("__mulint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__muluint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__divuint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__divint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__modint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__moduint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__modint16wo",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__divuint16wo",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__divint16wo",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__moduint16wo",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__modint16wo",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+
+ declare_builtin("__mulint32",LONG,LONG,FIRST_BIG+1,LONG,FIRST_BIG+2,1,0);
+ declare_builtin("__muluint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG+1,UNSIGNED|LONG,FIRST_BIG+2,1,0);
+ declare_builtin("__divint32",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+ declare_builtin("__divuint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+ declare_builtin("__modint32",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+ declare_builtin("__moduint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+ declare_builtin("__divint32wo",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+ declare_builtin("__divuint32wo",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+ declare_builtin("__modint32wo",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+ declare_builtin("__moduint32wo",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+
+
+
+ declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+ declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+ declare_builtin("__divint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__modint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__lsrint64",LLONG,LLONG,0,INT,0,1,0);
+ declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+ declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+
+ declare_builtin("__sint32toflt32",FLOAT,LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__uint32toflt32",FLOAT,UNSIGNED|LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__flt32tosint32",LONG,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__flt32touint32",UNSIGNED|LONG,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__sint16toflt32",FLOAT,INT,FIRST_PAIR,0,0,1,0);
+ declare_builtin("__uint16toflt32",FLOAT,UNSIGNED|INT,FIRST_PAIR,0,0,1,0);
+ declare_builtin("__flt32tosint16",INT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__flt32touint16",UNSIGNED|INT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+
+ declare_builtin("__sint32toflt64",DOUBLE,LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__uint32toflt64",DOUBLE,UNSIGNED|LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__flt64tosint32",LONG,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+ declare_builtin("__flt64touint32",UNSIGNED|LONG,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+ declare_builtin("__sint16toflt64",DOUBLE,INT,FIRST_PAIR,0,0,1,0);
+ declare_builtin("__uint16toflt64",DOUBLE,UNSIGNED|INT,FIRST_PAIR,0,0,1,0);
+ declare_builtin("__flt64tosint16",INT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+ declare_builtin("__flt64touint16",UNSIGNED|INT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+
+ declare_builtin("__flt64toflt32",FLOAT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+ declare_builtin("__flt32toflt64",DOUBLE,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+
+ declare_builtin("__addflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+ declare_builtin("__subflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+ declare_builtin("__mulflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+ declare_builtin("__divflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+ declare_builtin("__negflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__cmpsflt32",CHAR,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+
+#if 0
+ for(i=1;i<MAXR;i++){
+ printf("%02d %s scratch=%d ",i,regnames[i],regscratch[i]);
+ if(reg_pair(i,&rp))
+ printf("pair(%s,%s)",regnames[rp.r1],regnames[rp.r2]);
+ printf("\n");
+ }
+#endif
+
+ if(NOPEEP) nopeep=1;
+ if(CBMASCII) cbmascii=1;
+ if(ATASCII) atascii=1;
+ if(DIVBUG) divbug=1;
+ if(M65IO) m65io=1;
+ if(NOBANKING) manbank=1;
+ jmpinst="jmp";
+ if(C02||C02ALT){
+ c02=1;zzero=1;
+ jmpinst="bra";
+ }
+ if(CE02){
+ c02=1;ce02=1;
+ jmpinst="bra";
+ }
+ if(MEGA65){
+ m65=1;c02=1;ce02=1;
+ jmpinst="bra";
+ }
+
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+
+ bankv.storage_class=EXTERN;
+ bankv.identifier="__bankv";
+ bankv.vtyp=new_typ();
+ bankv.vtyp->flags=CHAR;
+
+ bankcnum=COMMONBANK;
+
+ return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+/* A pointer MUST be returned in a register. The code-generator */
+/* has to simulate a pseudo register if necessary. */
+{
+ int typ=t->flags&NQ;
+ if(ISSTRUCT(typ)||ISUNION(typ)||typ==VOID)
+ return 0;
+ if(OLDFP&&ISFLOAT(typ)) return FIRST_GPR;
+ if(typ==LONG||typ==FLOAT||ISFPOINTER(typ)||(!ieee&&(typ==DOUBLE||typ==LDOUBLE)))
+ return FIRST_BIG;
+ if(typ==LLONG||(ieee&&(typ==DOUBLE||typ==LDOUBLE)))
+ return FIRST_BIGP;
+ if(zmleq(szof(t),l2zm(1L)))
+ return ra;
+ if(zmleq(szof(t),l2zm(2L)))
+ return rax;
+ else
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ if(r>=FIRST_PAIR&&r<=LAST_PAIR){
+ p->r1=(r-FIRST_PAIR)*2+FIRST_GPR;
+ p->r2=p->r1+1;
+ return 1;
+ }else if(r>=FIRST_BIGP&&r<=LAST_BIGP){
+ p->r1=(r-FIRST_BIGP)*2+FIRST_BIG;
+ p->r2=p->r1+1;
+ return 1;
+ }else if(r==rax){
+ p->r1=ra;
+ p->r2=rx;
+ return 1;
+ }else if(r==sp){
+ p->r1=sp1;
+ p->r2=sp2;
+ return 1;
+ }
+ return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+ register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+ int c=p->code,co;
+ if((o->flags&VAR)&&(o->v->tattr&ZPAGE)) return 0;
+ if(indirect(o)) co=5; else co=2;
+
+ /*TODO: adapt this */
+ if(o->flags&VKONST){
+ if(o!=&p->q1||p->q2.flags!=0) return 0;
+ if(r==ra||r==rax) return co;
+ if(r==rx&&(c==ASSIGN||c==PUSH)) return co-1;
+ return 0;
+ }
+
+ if(ISIDX(r)){
+ if(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==AND||c==OR||c==XOR){
+ if(o==&p->q2&&c!=ADDI2P) return co-4;
+ if(r==rx&&o==&p->q2&&((p->q1.flags&(VARADR|KONST|VKONST))==0||(p->q1.flags&DREFOBJ)))
+ return co-4;
+ if((c==ADD||c==SUB)&&o==&p->z&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,q2typ(p));
+ if(zmeqto(vmax,Z1)&&zumeqto(vumax,ZU1))
+ return co+2;
+ }
+ }else if(c==ASSIGN||c==CONVERT){
+ if(o==&p->q1&&indirect(&p->z)) return 1;
+ if(o==&p->z&&indirect(&p->q1)) return 1;
+ }else if(c==COMPARE){
+ //if(o==&p->q1&&indirect(&p->q2)) return INT_MIN;
+ //if(o==&p->q2&&indirect(&p->q1)) return INT_MIN;
+ }else if(c==SETRETURN||c==GETRETURN||c==PUSH){
+ }else if(c==TEST){
+ }else
+ return INT_MIN;
+ }
+
+ if(c==ADDI2P&&o==&p->q1&&(p->typf&NU)==CHAR&&(r==rax))
+ return INT_MIN;
+
+
+ if(o->flags&DREFOBJ){
+ if(isptr(r))
+ return co+co+10;
+ if(r==rax)
+ return INT_MIN;
+ }
+ if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return co+2;
+ if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return co+2;
+ if((c==ADD||c==SUB)&&o==&p->z&&p->q1.flags==p->z.flags&&p->q1.v==p->z.v&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,q2typ(p));
+ if(zmeqto(vmax,Z1)&&zumeqto(vumax,ZU1))
+ return co+1;
+ }
+ if(r==ra)
+ return co+2;
+ if(ISIDX(r))
+ return co+1;
+ if(r==rax)
+ return co+co+4;
+ return co;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(r==0)
+ return 0;
+ if(r==rax&&NORAX)
+ return 0;
+ if(r==rx&&NOX)
+ return 0;
+ t&=NQ;
+ if(ISCHAR(t))
+ if(r==ra||(ISIDX(r)&&(optflags&2))||(r>=FIRST_GPR&&r<=LAST_GPR))
+ return 1;
+ if(ISSHORT(t)){
+ if(r==rax){
+ if(t==POINTER&&mode<0)
+ return 1;
+ if(t!=POINTER)
+ return 1;
+ }
+ if(r>=FIRST_PAIR&&r<=LAST_PAIR)
+ return 1;
+ }
+ if(r>=FIRST_BIG&&r<=LAST_BIG){
+ if(t==LONG||t==FLOAT||((t==DOUBLE||t==LDOUBLE)&&!ieee))
+ return 1;
+ if(t==FPOINTER)
+ return 1;
+ }
+ if(r>=FIRST_BIGP&&r<=LAST_BIGP){
+ if(t==LLONG||((t==DOUBLE||t==LDOUBLE)&&ieee))
+ return 1;
+ }
+ return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* On the PowerPC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op=o&NQ,tp=t&NQ;
+
+ if(op==tp) return 0;
+ if(ISCHAR(op)&&ISCHAR(tp)) return 0;
+ if(ISSHORT(op)&&ISSHORT(tp)) return 0;
+ if(!ieee&&ISFLOAT(op)&&ISFLOAT(tp)) return 0;
+ if(op==DOUBLE&&tp==LDOUBLE) return 0;
+ if(op==LDOUBLE&&tp==DOUBLE) return 0;
+
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ if(STDSYNTAX)
+ emit(f,"\tspace\t%ld\n",zm2l(size));
+ else
+ emit(f,"\treserve\t%ld\n",zm2l(size));
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ if(zm2l(align)>1) emit(f,"\talign 1\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag,b=sbank(v);char *sec;
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(v->tattr&ZPAGE)
+ emit(f,"\tzpage\t%s%ld\n",labprefix,zm2l(v->offset));
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))){emit(f,dataname);ebank(f,b);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)){emit(f,rodataname);ebank(f,b);if(f) section=RODATA;}
+ if(!v->clist){emit(f,bssname);ebank(f,b);if(f) section=BSS;}
+ }
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ newobj=1;
+ }
+ if(v->storage_class==EXTERN){
+ emit(f,"\t%s\t%s%s\n",(v->flags&NEEDS)?"needs":"global",idprefix,v->identifier);
+ if(v->tattr&ZPAGE)
+ emit(f,"\tzpage\t%s%s\n",idprefix,v->identifier);
+ if(v->flags&(DEFINED|TENTATIVE)){
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))){emit(f,dataname);ebank(f,b);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)){emit(f,rodataname);ebank(f,b);if(f) section=RODATA;}
+ if(!v->clist){emit(f,bssname);ebank(f,b);if(f) section=BSS;}
+ }
+
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ if(ISCHAR(t))
+ emit(f,"\tbyte\t");
+ else
+ emit(f,"\tword\t");
+ if(!p->tree){
+ if(ISLONG(t)||ISFLOAT(t)){
+ if(ieee&&ISFLOAT(t)){
+ emit_ieee(f,&p->val,t&NQ);
+ }else{
+ eval_const(&p->val,t&NU);
+ if(ISFLOAT(t)) cnv_fp();
+ gval.vmax=zmand(vmax,l2zm(0xffffL));
+ emitval(f,&gval,MAXINT);
+ emit(f,",");
+ gval.vmax=zmand(zmrshift(vmax,l2zm(16L)),l2zm(0xffffL));
+ emitval(f,&gval,MAXINT);
+ }
+ }else{
+ if(ISFPOINTER(t)){
+ eval_const(&p->val,t&NU);
+ emit(f,"%ld\n",(long)zm2l(vmax)&0xffff);
+ emit(f,"\tbyte\t%d\n",(int)((zm2l(vmax)>>16)&0xff));
+ }else
+ emitval(f,&p->val,t&NU);
+ }
+ }else{
+ emit_obj(f,&p->tree->o,t&NU);
+ if(ISFPOINTER(t)){
+ int b;
+ if((p->tree->o.flags&(VAR|VARADR))!=(VAR|VARADR)) ierror(0);
+ b=bank(p->tree->o.v);
+ emit(f,"\n\tbyte\t%d",b>=0?b:bankcnum);
+ }
+ }
+ emit(f,"\n");newobj=0;
+}
+
+static int handle_m65(FILE *f,IC *p)
+{
+ int t=p->typf,c=p->code,noop2=0;
+ if(c==MULT&&(ISSHORT(t)||ISCHAR(t))){
+ get_acc(f,p,INT);
+ load_acc(f,&p->q1,t);
+ if(m65io){
+ emit(f,"\tsta\t$d770\n");
+ if(ISSHORT(t)) emit(f,"\tstx\t$d771\n");
+ }else{
+ emit(f,"\tldz\t#$70\n");
+ emit(f,"\tstz\t___m65mathptr\n");
+ emit(f,"\tstq\t[___m65mathptr]\n");
+ }
+ load_acc(f,&p->q2,t);
+ if(m65io){
+ emit(f,"\tsta\t$d774\n");
+ if(ISSHORT(t)) emit(f,"\tstx\t$d775\n");
+ }
+ if(m65io){
+ emit(f,"\tlda\t$d778\n");
+ if(ISSHORT(t)) emit(f,"\tldx\t$d779\n");
+ }else{
+ emit(f,"\tldz\t#$74\n");
+ emit(f,"\tstz\t___m65mathptr\n");
+ emit(f,"\tstq\t[___m65mathptr]\n");
+ emit(f,"\tldz\t#4\n");
+ emit(f,"\tldq\t[___m65mathptr],z\n");
+ emit(f,"\tldz\t#0\n");
+ }
+ yval=NOVAL;
+ store_acc(f,&p->z,t);
+ return 1;
+ }
+ if(ISLONG(t)&&LONGM65(c)){
+ int mnoy;
+
+ if(c==ASSIGN&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg) return 1;
+ if(c==GETRETURN&&isreg(z)&&p->z.reg==FIRST_BIG) return 1;
+ if(c==SETRETURN&&isreg(q1)&&p->q1.reg==FIRST_BIG) return 1;
+
+ get_acc(f,p,INT);
+
+ if(c==LSHIFT||c==RSHIFT){
+ int r,cnt=-1,mzzero;
+
+ if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,p->typf2);
+ cnt=(int)(zm2l(vmax));
+ cnt&=31;
+ }
+
+ if(cnt==24||cnt==16||cnt==8||(cnt>=0&&(!optsize||cnt<=2))){
+ r=0;
+ }else{
+ if(isreg(q2)&&p->q2.reg>=FIRST_GPR&&scratch(p,r,0)){
+ r=p->q2.reg;
+ if(reg_pair(r,&rp)) r=rp.r1;
+ }else{
+ /* TODO: improve for x or z */
+ load_lobyte(f,&p->q2,p->typf2);
+ r=t1;
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ }
+ }
+
+ mzzero=zzero;
+ zzero=0;
+ if(cnt==24||(!optsize&&cnt>=24)){
+ cnt-=24;
+ if(c==LSHIFT){
+ if(indirect(&p->q1)){
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\ttaz\n");
+ }else
+ do_lobyte(f,"ldz",&p->q1,t);
+ emit(f,"\tlda\t#0\n");
+ emit(f,"\ttax\n");
+ emit(f,"\ttay\n");
+ yval=0;
+ }else if(t&UNSIGNED){
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tldx\t#0\n");
+ emit(f,"\tldz\t#0\n");
+ emit(f,"\tldy\t#0\n");
+ yval=0;
+ }else{
+ emit(f,"\tldx\t#0\n");
+ emit(f,"\tldz\t#0\n");
+ emit(f,"\tldy\t#0\n");
+ yval=0;
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdex\n");
+ if(yval==0)
+ emit(f,"\tdey\n");
+ emit(f,"\tdez\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(yval!=0){
+ emit(f,"\tphx\n");
+ emit(f,"\tply\n");
+ }
+ }
+ }else if(cnt==16||(!optsize&&cnt>=16)){
+ cnt-=16;
+ if(c==LSHIFT){
+ if(indirect(&p->q1)){
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\ttaz\n");
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\ttay\n");
+ }else{
+ do_lobyte(f,"ldy",&p->q1,t);
+ do_hibyte(f,"ldz",&p->q1,t);
+ }
+ emit(f,"\tlda\t#0\n");
+ emit(f,"\ttax\n");
+ }else if(t&UNSIGNED){
+ if(indirect(&p->q1)){
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\ttax\n");
+ do_byte3(f,"lda",&p->q1,t);
+ }else{
+ do_byte3(f,"lda",&p->q1,t);
+ do_byte4(f,"ldx",&p->q1,t);
+ }
+ emit(f,"\tldy\t#0\n");
+ emit(f,"\tldz\t#0\n");
+ }else{
+ emit(f,"\tldy\t#0\n");
+ emit(f,"\tldz\t#0\n");
+ yval=0;
+ if(indirect(&p->q1)){
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\ttax\n");
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tcpx\t#0\n");
+ }else{
+ do_byte3(f,"lda",&p->q1,t);
+ do_byte4(f,"ldx",&p->q1,t);
+ }
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdez\n");
+ if(yval==0)
+ emit(f,"\tdey\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(yval!=0){
+ emit(f,"\tphz\n");
+ emit(f,"\tply\n");
+ }
+ }
+ }else if(cnt==8||(!optsize&&cnt>=8)){
+ cnt-=8;
+ if(c==LSHIFT){
+ if(indirect(&p->q1)){
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\ttaz\n");
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\ttax\n");
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\ttay\n");
+ }else{
+ do_lobyte(f,"ldx",&p->q1,t);
+ do_byte3(f,"ldz",&p->q1,t);
+ do_hibyte(f,"ldy",&p->q1,t);
+ }
+ emit(f,"\tlda\t#0\n");
+ }else if(t&UNSIGNED){
+ emit(f,"\tldz\t#0\n");
+ if(indirect(&p->q1)){
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tpha\n");
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\ttax\n");
+ do_hibyte(f,"lda",&p->q1,t);
+ emit(f,"\tply\n");
+ }else{
+ do_hibyte(f,"lda",&p->q1,t);
+ do_byte3(f,"ldx",&p->q1,t);
+ do_byte4(f,"ldy",&p->q1,t);
+ }
+ }else{
+ emit(f,"\tldz\t#0\n");
+ if(indirect(&p->q1)){
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tpha\n");
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\ttax\n");
+ do_hibyte(f,"lda",&p->q1,t);
+ emit(f,"\tply\n");
+ }else{
+ do_hibyte(f,"lda",&p->q1,t);
+ do_byte3(f,"ldx",&p->q1,t);
+ do_byte4(f,"ldy",&p->q1,t);
+ }
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdez\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }else{
+ mnoy=noy;
+ ldq_offset(f,&p->q1);
+ noy=2;
+ emit(f,"\tldq\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ noy=mnoy;
+ }
+ if(r){
+ emit(f,"\tdec\t%s\n",mregnames[r]);
+ emit(f,"\tbmi\t%s%d\n",labprefix,++label);
+ emit(f,"%s%d:\n",labprefix,++label);
+ emit(f,"\t%s\n",c==LSHIFT?"aslq":((t&UNSIGNED)?"lsrq":"asrq"));
+ emit(f,"\tdec\t%s\n",mregnames[r]);
+ emit(f,"\tbpl\t%s%d\n",labprefix,label);
+ emit(f,"%s%d:\n",labprefix,label-1);
+ }else{
+ while(--cnt>=0)
+ emit(f,"\t%s\n",c==LSHIFT?"aslq":((t&UNSIGNED)?"lsrq":"asrq"));
+ }
+ yval=NOVAL;
+ mnoy=noy;
+ noy=1;
+ emit(f,"\tstq\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ noy=mnoy;
+ emit(f,"\tldz\t#0\n");
+ zzero=mzzero;
+ return 1;
+ }
+
+ if(c==PUSH){
+ if(pushed){
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ emit(f,"\tldx\t%s+1\n",mregnames[sp]);
+ emit(f,"\tclc\n");
+ emit(f,"\tadc\t#%d\n",pushed);
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ emit(f,"\tinx\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tsta\t%s\n",mregnames[t1]);
+ emit(f,"\tstx\t%s\n",mregnames[t2]);
+ }
+ pushed+=4;
+ }
+ if((c==MULT||c==DIV)&&!m65io){
+ emit(f,"\tlda\t#$70\n");
+ emit(f,"\tsta\t___m65mathptr\n");
+ }
+ yval=NOVAL;
+ noy=1;
+ if((p->q1.flags&(KONST|DREFOBJ))==KONST){
+ unsigned long v;
+ eval_const(&p->q1.val,q1typ(p));
+ v=zum2ul(vumax);
+ emit(f,"\tlda\t#%d\n",(int)(v&255));v>>=8;
+ emit(f,"\tldx\t#%d\n",(int)(v&255));v>>=8;
+ emit(f,"\tldy\t#%d\n",(int)(v&255));v>>=8;
+ emit(f,"\tldz\t#%d\n",(int)(v&255));
+ }else if(c==GETRETURN){
+ emit(f,"\tldq\t%s\n",mregnames[FIRST_BIG]);
+ }else{
+ noy=2;
+ ldq_offset(f,&p->q1);
+ emit(f,"\tldq\t");
+ /*TODO: VARADR */
+ if((p->q1.flags&VARADR)||(p->q1.flags&(KONST|DREFOBJ))==KONST){
+ emit(f,"%s%d",labprefix,addfpconst(&p->q1,q1typ(p)));
+ }else
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ noy=1;
+ }
+ if(c==ADD){
+ if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,t);
+ if(zmeqto(vmax,Z1)){noop2=1;emit(f,"\tinq\n");}
+ else if(zmeqto(vmax,l2zm(2L))){noop2=1;emit(f,"\tinq\n\tinq\n");}
+ else if(zmeqto(vmax,l2zm(3L))){noop2=1;emit(f,"\tinq\n\tinq\n\tinq\n");}
+ else if(zmeqto(vmax,l2zm(4L))){noop2=1;emit(f,"\tinq\n\tinq\n\tinq\n\tinq\n");}
+ }
+ if(!noop2){
+ emit(f,"\tclc\n");
+ emit(f,"\tadcq\t");
+ }
+ }else if(c==SUB){
+ if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,t);
+ if(zmeqto(vmax,Z1)){noop2=1;emit(f,"\tdeq\n");}
+ else if(zmeqto(vmax,l2zm(2L))){noop2=1;emit(f,"\tdeq\n\tdeq\n");}
+ else if(zmeqto(vmax,l2zm(3L))){noop2=1;emit(f,"\tdeq\n\tdeq\n\tdeq\n");}
+ else if(zmeqto(vmax,l2zm(4L))){noop2=1;emit(f,"\tdeq\n\tdeq\n\tdeq\n\tdeq\n");}
+ }
+ if(!noop2){
+ emit(f,"\tsec\n");
+ emit(f,"\tsbcq\t");
+ }
+ }else if(c==OR){
+ emit(f,"\torq\t");
+ }else if(c==AND){
+ emit(f,"\tandq\t");
+ }else if(c==XOR){
+ emit(f,"\teorq\t");
+ }else if(c==MULT||c==DIV){
+ if(m65io){
+ emit(f,"\tstq\t$d770\n");
+ }else{
+ emit(f,"\tstq\t[___m65mathptr]\n");
+ emit(f,"\tlda\t#$74\n");
+ emit(f,"\tsta\t___m65mathptr\n");
+ }
+ noy=2;
+ ldq_offset(f,&p->q2);
+ emit(f,"\tldq\t");
+ }
+ if(c!=ASSIGN&&c!=PUSH&&c!=GETRETURN&&c!=SETRETURN&&!noop2){
+ if((p->q2.flags&VARADR)||(p->q2.flags&(KONST|DREFOBJ))==KONST){
+ emit(f,"%s%d",labprefix,addfpconst(&p->q2,q2typ(p)));
+ }else
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+ noy=1;
+ if(c==MULT||c==DIV){
+ if(m65io)
+ emit(f,"\tstq\t$d774\n");
+ else
+ emit(f,"\tstq\t[___m65mathptr]\n");
+ if(m65io){
+ if(c==DIV){
+ /* delay */
+ emit(f,"\tlda\t$d76c\n");
+ emit(f,"\tlda\t$d76c\n");
+ emit(f,"\tlda\t$d76c\n");
+ emit(f,"\tlda\t$d76c\n");
+ emit(f,"\tldq\t$d76c\n");
+ }else
+ emit(f,"\tldq\t$d778\n");
+ }else{
+ if(c==DIV){
+ emit(f,"\tlda\t#$6c\n");
+ emit(f,"\tsta\t___m65mathptr\n");
+ emit(f,"\tldz\t#0\n");
+ emit(f,"\tlda\t[___m65mathptr],z\n"); /* delay for division */
+ }else
+ emit(f,"\tldz\t#4\n");
+ emit(f,"\tldq\t[___m65mathptr],z\n");
+ }
+ }
+ emit(f,"\tstq\t");
+ if(c==PUSH)
+ emit(f,"(%s)",pushed==4?mregnames[sp]:mregnames[t1]);
+ else if(c==SETRETURN)
+ emit(f,"%s",mregnames[FIRST_BIG]);
+ else
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ noy=0;
+ if(zzero)
+ emit(f,"\tldz\t#0\n");
+ else
+ ierror(0);
+ return 1;
+ }
+ return 0;
+}
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/* The main code-generation. */
+{
+ int c,t,i;
+ struct IC *mi;
+ FILE *rf=f;
+ static char *dbgfile;
+ static int dbgline;
+
+ if(vlas){
+ fp=FPVLA_REG;
+ if(!reg_pair(fp,&rp)) ierror(0);
+ fp1=rp.r1;
+ fp2=rp.r2;
+ regused[fp]=regused[fp1]=regused[fp2]=1;
+ }else{
+ fp=sp;
+ fp1=sp1;
+ fp2=sp2;
+ }
+ argsize=0;
+ localsize=offset;
+ if(DEBUG&1) printf("gen_code()\n");
+
+ if(ce02) zzero=1; /* TODO: check what to do */
+
+ cbank=bank(v);
+
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_REGS;
+
+ for(mi=p;mi;mi=mi->next)
+ switch_IC(mi);
+
+ for(pass=0;pass<2;pass++){
+
+ if(DEBUG&1) printf("pass %d\n",pass);
+
+ if(pass==0){
+ f=0;
+ mi=clone_ic(p);
+ }else
+ f=rf;
+
+ for(c=1;c<=MAXR;c++) regs[c]=0; /*regsa[c];*/
+ maxpushed=0;
+
+ /*FIXME*/
+ if(v->tattr&INTERRUPT){
+ ret="\trti\n";
+ in_isr=1;
+ }else{
+ ret="\trts\n";
+ in_isr=0;
+ }
+
+ if(!nopeep) peephole(pass==0?p:mi);
+
+ function_top(f,v,localsize);
+
+ pushed=0;
+
+ yval=NOVAL;
+
+ dbgfile=0;
+ dbgline=0;
+
+ for(p=pass==0?p:mi;p;pr(f,p),p=p->next){
+
+
+
+ if(DEBUG&1) pric2(stdout,p);
+
+ if(debug_info){
+ if(p->file&&p->line){
+ if(p->file!=dbgfile||p->line!=dbgline){
+ dbgfile=p->file;
+ dbgline=p->line;
+ emit(f,"; %d \"%s\"\n",dbgline,dbgfile);
+ }
+ }
+ }
+
+ c=p->code;t=p->typf;
+
+ if(c==NOP) {p->z.flags=0;continue;}
+ if(c==ALLOCREG){
+ regs[p->q1.reg]=1;
+ if(reg_pair(p->q1.reg,&rp)){
+ regs[rp.r1]=1;
+ regs[rp.r2]=1;
+ }
+ continue;
+ }
+ if(c==FREEREG){
+ regs[p->q1.reg]=0;
+ if(reg_pair(p->q1.reg,&rp)){
+ regs[rp.r1]=0;
+ regs[rp.r2]=0;
+ }
+ continue;
+ }
+ if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);yval=NOVAL;continue;}
+ if(c==BRA){
+ yval=NOVAL;
+ if(t==exit_label&&localsize+argsize+rsavesize+rscnt==0)
+ emit(f,ret);
+ else
+ emit(f,"\t%s\t%s%d\n",jmpinst,labprefix,t);
+ continue;
+ }
+ if(c>=BEQ&&c<BRA){
+ yval=NOVAL;
+ continue;
+ }
+
+ if(c==MOVETOREG){
+ p->code=c=ASSIGN;
+ p->typf=t=regtype[p->z.reg]->flags;
+ p->q2.val.vmax=sizetab[regtype[p->z.reg]->flags];
+ }
+ if(c==MOVEFROMREG){
+ p->code=c=ASSIGN;
+ p->typf=t=regtype[p->q1.reg]->flags;
+ p->q2.val.vmax=sizetab[regtype[p->q1.reg]->flags];
+ }
+ if(c==CONVERT&&ISCHAR(t)&&ISCHAR(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[CHAR];
+ }
+ if(c==CONVERT&&msizetab[t&NQ]==3&&msizetab[p->typf2&NQ]==3){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[SHORT];
+ }
+ if(c==CONVERT&&ISSHORT(t)&&ISSHORT(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[SHORT];
+ }
+ if(c==CONVERT&&ISLONG(t)&&ISLONG(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[LONG];
+ }
+ if(c==CONVERT&&ISLLONG(t)&&ISLLONG(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[LLONG];
+ }
+ if(c==CONVERT&&ISFLOAT(t)&&ISFLOAT(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[t&NQ];
+ }
+
+
+ /* switch commutative operands if suitable */
+ if(c==ADD||c==MULT||c==AND||c==XOR||c==OR||(c==ADDI2P&&ISSHORT(t)&&!ISFPOINTER(p->typf2))){
+ if((compare_objects(&p->q2,&p->z)&&!isacc(q1))||isacc(q2)){
+ struct obj tmp;
+ tmp=p->q1;
+ p->q1=p->q2;
+ p->q2=tmp;
+ }
+ }
+
+ if(c==COMPARE&&((p->q1.flags&(KONST|DREFOBJ))==KONST||ISRIDX(q2)||(isacc(q2)&&!ISRIDX(q1)))){
+ obj tmp;IC *b;
+ tmp=p->q1;
+ p->q1=p->q2;
+ p->q2=tmp;
+ for(b=p->next;b;b=b->next){
+ int bc;
+ if(!b||b->code==LABEL) ierror(0);
+ bc=b->code;
+ if(bc==BGT){b->code=BLT;break;}
+ if(bc==BGE){b->code=BLE;break;}
+ if(bc==BLT){b->code=BGT;break;}
+ if(bc==BLE){b->code=BGE;break;}
+ if(bc==BNE||bc==BEQ) break;
+ }
+ }
+
+ c=p->code;
+ if(c==SUBPFP) c=SUB;
+ /*if(c==ADDI2P) c=ADD;*/
+ /*if(c==SUBIFP) c=SUB;*/
+
+
+ if(c==MINUS){
+ if(isacc(q1)&&isacc(z)){
+ emit(f,"\teor\t#255\n");
+ if(c02&&ISCHAR(t)){
+ emit(f,"\tina\n");
+ }else{
+ emit(f,"\tclc\n");
+ emit(f,"\tadc\t#1\n");
+ }
+ if(!ISCHAR(t)){
+ emit(f,"\tpha\n");
+ emit(f,"\ttxa\n");
+ emit(f,"\teor\t#255\n");
+ emit(f,"\tadc\t#0\n");
+ emit(f,"\ttax\n");
+ emit(f,"\tpla\n");
+ }
+ continue;
+ }
+ p->code=c=SUB;
+ p->q2=p->q1;
+ p->q1.flags=KONST;
+ p->q1.am=0;
+ gval.vmax=Z0;
+ eval_const(&gval,MAXINT);
+ insert_const(&p->q1.val,t);
+ }
+
+ preload(f,p);
+
+ if((c==ADD||c==SUB||c==ADDI2P||c==SUBIFP)&&compare_objects(&p->q1,&p->z)&&(!indirect(&p->q1)||(isreg(q1)&&ISIDX(p->q1.reg)))&&isconst(q2)&&!isacc(z)){
+ long l;
+ eval_const(&p->q2.val,q2typ(p));
+ l=zm2l(vmax);
+ if(c==ADDI2P/*&&(t2&NQ)==POINTER*/) {c=ADD;t=UNSIGNED|INT;}
+ if(c==SUBIFP/*&&(t2&NQ)==POINTER*/) {c=SUB;t=UNSIGNED|INT;}
+ if(c==SUB||c==SUBIFP) l=-l;
+ /*TODO: allow larger types */
+ if(l<3&&l>-3&&(t&NQ)<=INT){
+ if(l<0){
+ if(!c02||!isreg(q1)) get_acc(f,p,CHAR);
+ incmem(f,&p->z,t,SUB,-l);
+ }else
+ incmem(f,&p->z,t,ADD,l);
+ continue;
+ }
+ if(ISLONG(t)&&((m65&&labs(l)<3)||(optspeed&&l>0&&l<4)||(l>0&&l<2))){
+ if(l<0){
+ incmem(f,&p->z,t,SUB,-l);
+ }else
+ incmem(f,&p->z,t,ADD,l);
+ continue;
+ }
+ }
+
+ if(m65&&handle_m65(f,p))
+ continue;
+
+ if(c==CONVERT){
+ int to=q1typ(p)&NU;
+ t&=NU;
+ if(ISCHAR(t)){
+ if(!isacc(q1))
+ get_acc(f,p,CHAR);
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+ continue;
+ }
+ if(ISLONG(to)){
+ if(!isacc(z))
+ get_acc(f,p,CHAR);
+ if(zm2l(sizetab[t&NQ])==3){
+ do_byte3(f,"lda",&p->q1,to);
+ do_byte3(f,"sta",&p->z,t);
+ }
+ if(zm2l(sizetab[t&NQ])>=2){
+ if(isacc(z)&&!indirect(&p->q1)){
+ do_hibyte(f,"ldx",&p->q1,to);
+ }else{
+ load_hibyte(f,&p->q1,to);
+ store_hibyte(f,&p->z,t);
+ }
+ }
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+ continue;
+ }
+ if(ISSHORT(to)){
+ if((t&UNSIGNED)||ISFPOINTER(t))
+ get_acc(f,p,CHAR);
+ else
+ get_acc(f,p,SHORT);
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+ load_hibyte(f,&p->q1,to);
+ store_hibyte(f,&p->z,t);
+ if(ISFPOINTER(t)){
+ int b=-1;
+ if((p->q1.flags&(VARADR|DREFOBJ))==VARADR) b=bank(p->q1.v);
+ emit(f,"\tlda\t#%d\n",b>=0?b:bankcnum);
+ do_byte3(f,"sta",&p->z,t);
+ continue;
+ }
+ if(to&UNSIGNED){
+ if(zzero&&!indirect(&p->z)){
+ do_byte3(f,"stz",&p->z,t);
+ do_byte4(f,"stz",&p->z,t);
+ }else{
+ emit(f,"\tlda\t#0\n");
+ do_byte3(f,"sta",&p->z,t);
+ do_byte4(f,"sta",&p->z,t);
+ }
+ }else{
+ emit(f,"\tldx\t#0\n");
+ emit(f,"\tcmp\t#0\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdex\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(indirect(&p->z)){
+ emit(f,"\ttxa\n");
+ do_byte3(f,"sta",&p->z,t);
+ do_byte4(f,"sta",&p->z,t);
+ }else{
+ do_byte3(f,"stx",&p->z,t);
+ do_byte4(f,"stx",&p->z,t);
+ }
+ }
+ continue;
+ }
+ if(ISCHAR(to)){
+ if(to&UNSIGNED){
+ char *s;
+ get_acc(f,p,CHAR);
+ if(isreg(q1)&&p->q1.reg==rx&&!indirect(&p->z)){
+ do_lobyte(f,"stx",&p->z,CHAR);
+ }else{
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+ }
+ if(isacc(z)){
+ emit(f,"\tldx\t#0\n");
+ continue;
+ }
+ if(zzero&&!indirect(&p->z))
+ s="stz";
+ else{
+ emit(f,"\tlda\t#0\n");
+ s="sta";
+ }
+ do_hibyte(f,s,&p->z,t);
+ if(ISLONG(t)){
+ do_byte3(f,s,&p->z,t);
+ do_byte4(f,s,&p->z,t);
+ }
+ }else{
+ int l=++label;
+ get_acc(f,p,SHORT);
+ emit(f,"\tldx\t#0\n");
+ if(isreg(q1)&&p->q1.reg==ra)
+ emit(f,"\tcmp\t#0\n");
+ else
+ load_lobyte(f,&p->q1,to);
+ emit(f,"\tbpl\t%s%d\n",labprefix,label);
+ emit(f,"\tdex\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ store_lobyte(f,&p->z,t);
+ if(indirect(&p->z)&&(!isreg(z)||p->z.reg!=rax)){
+ emit(f,"\ttxa\n");
+ store_hibyte(f,&p->z,t);
+ if(ISLONG(t)){
+ do_byte3(f,"sta",&p->z,t);
+ do_byte4(f,"sta",&p->z,t);
+ }
+ }else{
+ if(!isreg(z)||p->z.reg!=rax){
+ emit(f,"\tstx\t");
+ emit_hibyte(f,&p->z,t);
+ emit(f,"\n");
+ }
+ if(ISLONG(t)){
+ do_byte3(f,"stx",&p->z,t);
+ do_byte4(f,"stx",&p->z,t);
+ }
+ }
+ }
+ if(ISFPOINTER(t)){
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ do_byte3(f,"sta",&p->z,t);
+ }
+ continue;
+ }
+ if(ISFPOINTER(to)){
+ get_acc(f,p,CHAR);
+ if(zm2l(sizetab[t&NQ])>=3){
+ do_byte3(f,"lda",&p->q1,to);
+ do_byte3(f,"sta",&p->z,t);
+ }
+ if(zm2l(sizetab[t&NQ])>=2){
+ load_hibyte(f,&p->q1,to);
+ store_hibyte(f,&p->z,t);
+ }
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+
+ continue;
+ }
+ pric2(stdout,p);
+ ierror(0);
+ }
+
+ if(c==KOMPLEMENT){
+ get_acc(f,p,CHAR);
+ if(ISCHAR(t)){
+ load_acc(f,&p->q1,t);
+ emit(f,"\teor\t#-1\n");
+ store_acc(f,&p->z,t);
+ }else{
+ if(isacc(q1))
+ emit(f,"\tpha\n");
+ if(ISLONG(t)){
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\teor\t#-1\n");
+ do_byte4(f,"sta",&p->z,t);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\teor\t#-1\n");
+ do_byte3(f,"sta",&p->z,t);
+ }
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\teor\t#-1\n");
+ store_hibyte(f,&p->z,t);
+ if(isacc(q1))
+ emit(f,"\tpla\n");
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\teor\t#-1\n");
+ store_lobyte(f,&p->z,t);
+ }
+ continue;
+ }
+ if(c==SETRETURN){
+ hasretval=1;
+ t&=NQ;
+ if(isreg(q1)&&p->q1.reg==p->z.reg) continue;
+ if(t==LONG||t==LLONG||ISFLOAT(t)||ISFPOINTER(t)){
+ long l=zm2l(p->q2.val.vmax);
+ int zr=p->z.reg;
+ //get_acc(f,p,t);
+ if((optsize||l>4)&&!ISFPOINTER(t)){
+ int ind=indirect(&p->q1);
+ if(ind) load_address(f,LAST_PAIR,&p->q1,t);
+ BSET(regused,t3);
+ BSET(regused,t4);
+ sety(f,l-1);
+ emit(f,"%s%d:\n",labprefix,++label);
+ if(ind)
+ emit(f,"\tlda\t(%s),y\n",mregnames[LAST_PAIR]);
+ else{
+ emit(f,"\tlda\t");
+ if(!ISFLOAT(t)&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+ emit(f,"%s%d",labprefix,addfpconst(&p->q1,t));
+ }else
+ emit_obj(f,&p->q1,t);
+ emit(f,",y\n");
+ }
+ emit(f,"\tsta\t%s,y\n",mregnames[zr]);
+ emit(f,"\tdey\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,label);
+ yval=255;
+ }else{
+ if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ if(p->q1.reg==zr){
+ int r=get_reg(f,p,POINTER);
+ if(r==FIRST_PAIR||r==FIRST_PAIR+1)
+ ierror(0);
+ if(!reg_pair(r,&rp2)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[zr]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tlda\t%s+1\n",mregnames[zr]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+ p->q1.reg=r;
+ }
+ }
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[zr]);
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s+1\n",mregnames[zr]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s+2\n",mregnames[zr]);
+ if(!ISFPOINTER(t)){
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s+3\n",mregnames[zr]);
+ }
+ /*TODO:regused OLDFP */
+ regused[zr]=1;
+ }
+ continue;
+ }
+ //get_acc(f,p,t);
+ load_acc(f,&p->q1,t);
+ regused[ra]=1;
+ regused[rx]=1;
+ continue;
+ }
+ if(c==GETRETURN){
+ t&=NQ;
+ if(isreg(z)&&p->q1.reg==p->z.reg) continue;
+ if(t==LONG||t==LLONG||ISFLOAT(t)||ISFPOINTER(t)){
+ long l=zm2l(p->q2.val.vmax);
+ int qr=p->q1.reg;
+ if((optsize||l>4)&&!ISFPOINTER(t)){
+ int ind=indirect(&p->z);
+ if(ind) load_address(f,LAST_PAIR,&p->z,t);
+ BSET(regused,t3);
+ BSET(regused,t4);
+ sety(f,l-1);
+ emit(f,"%s%d:\n",labprefix,++label);
+ emit(f,"\tlda\t%s,y\n",mregnames[qr]);
+ if(ind)
+ emit(f,"\tsta\t(%s),y\n",mregnames[LAST_PAIR]);
+ else{
+ emit(f,"\tsta\t");
+ emit_obj(f,&p->z,t);
+ emit(f,",y\n");
+ }
+ emit(f,"\tdey\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,label);
+ yval=255;
+ }else{
+ if((p->z.reg&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ if(p->z.reg==qr) ierror(0);
+ }
+ emit(f,"\tlda\t%s\n",mregnames[qr]);
+ store_lobyte(f,&p->z,t);
+ emit(f,"\tlda\t%s+1\n",mregnames[qr]);
+ store_hibyte(f,&p->z,t);
+ emit(f,"\tlda\t%s+2\n",mregnames[qr]);
+ do_byte3(f,"sta",&p->z,t);
+ if(!ISFPOINTER(t)){
+ emit(f,"\tlda\t%s+3\n",mregnames[qr]);
+ do_byte4(f,"sta",&p->z,t);
+ }
+ }
+ continue;
+ }
+ if(p->q1.reg)
+ store_acc(f,&p->z,t);
+ continue;
+ }
+ if(c==CALL){
+ int reg;
+
+ if(argsize<zm2l(p->q2.val.vmax)) argsize=zm2l(p->q2.val.vmax);
+
+ /*FIXME*/
+#if 0
+ if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+ if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+ stack=framesize+zum2ul(p->q1.v->fi->stack1);
+ }else
+ stack_valid=0;
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+ long of=va_offset(v)+localsize+rsavesize+argsize;
+ emit(f,"\tlda\t%s\n",mregnames[fp]);
+ if(of){
+ emit(f,"\tclc\n");
+ if(of&255)
+ emit(f,"\tadc\t#%d\n",(of&255));
+ }
+ emit(f,"\tldx\t%s+1\n",mregnames[fp]);
+ if(of&0xff00){
+ emit(f,"\tpha\n");
+ emit(f,"\ttxa\n");
+ emit(f,"\tadc\t#%d\n",(of>>8)&255);
+ emit(f,"\ttax\n");
+ emit(f,"\tpla\n");
+ }else if(of){
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ emit(f,"\tinx\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ continue;
+ }
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit(f,";startinline\n");
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ emit(f,";endinline\n");
+ }else if(p->q1.flags&DREFOBJ){
+ if(ISFPOINTER(p->q1.dtyp)){
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,LAST_PAIR,&p->q1,POINTER);
+ if(indirect(&p->q1)){
+ do_byte3(f,"lda",&p->q1,FPOINTER);
+ emit(f,"\ttay\n");
+ }else
+ do_byte3(f,"ldy",&p->q1,FPOINTER);
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ emit(f,"\tjsr\t%s__bankjsr\n",idprefix);
+ yval=NOVAL;
+ }else{
+ if(!(p->q1.flags®)) ierror(0);
+ emit(f,"\tjsr\t%s%d\n",labprefix,++label);
+ yval=NOVAL;
+ add_cmplist(label,p->q1.reg,JMPIND);
+ }
+ }else{
+ int tbank=-1;
+ if(p->q1.flags&VAR) tbank=bank(p->q1.v);
+ if(tbank!=cbank&&tbank>=0){
+ if(cbank>=0){
+ load_address(f,LAST_PAIR,&p->q1,t);
+ sety(f,tbank);
+ emit(f,"\tlda\t#%d\n",cbank);
+ emit(f,"\tjsr\t%s__bankjsr\n",idprefix);
+ yval=NOVAL;
+ continue;
+ }
+ sety(f,tbank);
+ emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+ yval=NOVAL;
+ }
+ if((p->q1.flags&VAR)&&!strcmp(p->q1.v->identifier,"_fmemcpy"))
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ emit(f,"\tjsr\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ pushed-=zm2l(p->q2.val.vmax);
+ if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS;
+ yval=NOVAL;
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(t==0) ierror(0);
+ if((p->q1.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)==LLONG){
+ int i;
+ eval_const(&p->q1.val,t);
+ for(i=0;i<8;i++){
+ emit(f,"\tlda\t#%d\n",zm2l(vmax)&255);
+ vmax=zmrshift(vmax,l2zm(8L));
+ if(c==PUSH||(p->z.flags&DREFOBJ)){
+ sety(f,i+((c==PUSH)?pushed:0));
+ emit(f,"\tsta\t(%s),y\n",(c==PUSH)?mregnames[sp]:mregnames[p->z.reg]);
+ }else{
+ p->z.val.vmax=zmadd(p->z.val.vmax,l2zm((long)i));
+ emit(f,"\tsta\t");
+ emit_lobyte(f,&p->z,t);
+ emit(f,"\n");
+ p->z.val.vmax=zmsub(p->z.val.vmax,l2zm((long)i));
+ }
+ }
+ if(c==PUSH) pushed+=8;
+ continue;
+ }
+
+ if(!zmleq(p->q2.val.vmax,l2zm(4L))){
+ long len=zm2l(p->q2.val.vmax);
+ int r1,r2,loops,looplab;
+ if(len>32767) ierror(0);
+ if(!NOBANKVARS){
+ int bq=-1,bz=-1,s=-1;
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR) bq=bank(p->q1.v);
+ if((p->z.flags&(VAR|DREFOBJ))==VAR) bz=bank(p->z.v);
+ if(((p->q1.flags&DREFOBJ)&&ISFPOINTER(p->q1.dtyp))||
+ ((p->z.flags&DREFOBJ)&&ISFPOINTER(p->z.dtyp))){
+ far_copy(f,p);
+ continue;
+ }
+ if(cbank<0){
+ if(bq>=0&&bz>=0){
+ if(bq!=bz){
+ far_copy(f,p);
+ continue;
+ }
+ s=bq;
+ }else{
+ if(bq>=0) s=bq;
+ if(bz>=0) s=bz;
+ }
+ if(s>=0){
+ sety(f,s);
+ emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+ yval=NOVAL;
+ }
+ }else{
+ if((bq>=0&&bq!=cbank)||(bz>=0&&bz!=cbank)){
+ far_copy(f,p);
+ continue;
+ }
+ }
+ }
+ get_acc(f,p,CHAR);
+ if((p->q1.flags&(DREFOBJ|KONST))==DREFOBJ){
+ if(p->q1.flags®){
+ r1=p->q1.reg;
+ if(!reg_pair(r1,&rp)) ierror(0);
+ if(len>128){
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tclc\n");
+ if(len&128)
+ emit(f,"\tadc\t#128\n");
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ if(len>255){
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tadc\t#%ld\n",(len>>8)&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ }else{
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ emit(f,"\tinc\t%s\n",mregnames[rp.r2]);
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }
+ }else
+ ierror(0);
+ }else if(!indirect(&p->q1)&&len<=128&&(p->q1.flags&(DREFOBJ|KONST))!=KONST){
+ r1=0;
+ }else{
+ Var *v=p->q1.v;
+ /*if((p->q1.flags&(VARADR|VAR))!=VAR) ierror(0);*/
+ /*printf("len=%ld %ld\n",len,len&0xff80);*/
+ r1=get_reg(f,p,POINTER);
+ if(len>128) p->q1.val.vmax=zmadd(p->q1.val.vmax,l2zm((len-1)&0xff80));
+ load_address(f,r1,&p->q1,t);
+ if(len>128) p->q1.val.vmax=zmsub(p->q1.val.vmax,l2zm((len-1)&0xff80));
+ }
+ if((p->z.flags&(DREFOBJ|KONST))==DREFOBJ){
+ if(p->z.flags®){
+ r2=p->z.reg;
+ if(!reg_pair(r2,&rp)) ierror(0);
+ if(len>128){
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tclc\n");
+ if(len&128)
+ emit(f,"\tadc\t#128\n");
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ if(len>255){
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tadc\t#%ld\n",(len>>8)&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ }else{
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ emit(f,"\tinc\t%s\n",mregnames[rp.r2]);
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }
+ }else
+ ierror(0);
+ }else if(c==PUSH){
+ if(len<=128&&pushed==0){
+ r2=sp;
+ }else{
+ r2=get_reg(f,p,POINTER);
+ if(!reg_pair(r2,&rp)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ emit(f,"\tclc\n");
+ if(((pushed+(len&128))&255)!=0)
+ emit(f,"\tadc\t#%ld\n",(pushed+(len&128))&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[sp2]);
+ emit(f,"\tadc\t#%ld\n",((pushed+len)>>8)&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ }
+ }else if(!indirect(&p->z)&&len<=128){
+ r2=0;
+ }else{
+ Var *v=p->z.v;
+ r2=get_reg(f,p,POINTER);
+ if(len>128) p->z.val.vmax=zmadd(p->z.val.vmax,l2zm((len-1)&0xff80));
+ load_address(f,r2,&p->z,t);
+ if(len>128) p->z.val.vmax=zmsub(p->z.val.vmax,l2zm((len-1)&0xff80));
+ }
+ if(len>128){
+ get_acc(f,p,POINTER); /* get x */
+ emit(f,"\tldx\t#%ld\n",(((len-128)>>7)+1)&255);
+ }
+ sety(f,(len-1)&127);
+ if((optsize&&len>4)||len>8){
+ emit(f,"%s%d:\n",labprefix,looplab=++label);
+ if(optsize)
+ loops=1;
+ else{
+ if((len&3)==0)
+ loops=4;
+ else if((len&1)==0)
+ loops=2;
+ else
+ loops=1;
+ }
+ }else
+ loops=len;
+ if(r1&&!reg_pair(r1,&rp)) ierror(0);
+ if(r2&&!reg_pair(r2,&rp2)) ierror(0);
+ for(i=0;i<loops;i++){
+ if(r1)
+ emit(f,"\tlda\t(%s),y\n",mregnames[rp.r1]);
+ else{
+ emit(f,"\tlda\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,",y\n");
+ }
+ if(r2)
+ emit(f,"\tsta\t(%s),y\n",mregnames[rp2.r1]);
+ else{
+ emit(f,"\tsta\t");
+ emit_obj(f,&p->z,t);
+ emit(f,",y\n");
+ }
+ emit(f,"\tdey\n");
+ }
+ if(loops!=len){
+ emit(f,"\tbpl\t%s%d\n",labprefix,label);
+ }
+ if(len>128){
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tsec\n");
+ emit(f,"\tsbc\t#128\n");
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+ emit(f,"\tdec\t%s\n",mregnames[rp.r2]);
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tlda\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tsec\n");
+ emit(f,"\tsbc\t#128\n");
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+ emit(f,"\tdec\t%s\n",mregnames[rp2.r2]);
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tldy\t#127\n");
+ emit(f,"\tdex\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,looplab);
+ }
+ yval=NOVAL;
+ if(c==PUSH)
+ pushed+=zm2l(p->q2.val.vmax);
+ continue;
+ }
+ if(c==PUSH){
+ if(!scratch(p->next,ra,1))
+ get_acc(f,p,CHAR);
+ load_lobyte(f,&p->q1,t);
+ if(zzero&&pushed==0){
+ emit(f,"\tsta\t(%s)\n",mregnames[sp]);
+ }else{
+ sety(f,pushed);
+ emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+ }
+ if(!zmleq(p->q2.val.vmax,Z1)){
+ load_hibyte(f,&p->q1,t);
+ sety(f,pushed+1);
+ emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+ }
+ if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+ do_byte3(f,"lda",&p->q1,t);
+ sety(f,pushed+2);
+ emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+ }
+ if(!zmleq(p->q2.val.vmax,l2zm(3L))){
+ do_byte4(f,"lda",&p->q1,t);
+ sety(f,pushed+3);
+ emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+ }
+
+ pushed+=zm2l(p->q2.val.vmax);
+ continue;
+ }
+ if(c==ASSIGN){
+ int c2m;unsigned long v;
+ if(isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg) continue;
+ if(isacc(q1)){
+ if(p->q1.reg==rax&&indirect(&p->z)) get_acc(f,p,CHAR);
+ store_acc(f,&p->z,t);
+ continue;
+ }
+ if(zzero&&!indirect(&p->z)&&(p->q1.flags&(DREFOBJ|KONST))==KONST){
+ eval_const(&p->q1.val,t);
+ if(ISFLOAT(t)){
+ cnv_fp();
+ v=zum2ul(zm2zum(vmax));
+ }else
+ v=zum2ul(vumax);
+ c2m=1;
+ }else
+ c2m=0;
+ if(!c2m||v!=0)
+ get_acc(f,p,CHAR);
+ if(0/*ISCHAR(t)*/){
+ load_acc(f,&p->q1,t);
+ store_acc(f,&p->z,t);
+ }else{
+ if(!zmleq(p->q2.val.vmax,l2zm(3L))){
+ if(c2m&&(v&0xFF000000)==0){
+ do_byte4(f,"stz",&p->z,t);
+ }else{
+ do_byte4(f,"lda",&p->q1,t);
+ do_byte4(f,"sta",&p->z,t);
+ }
+ }
+ if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+ if(c2m&&(v&0xFF0000)==0){
+ do_byte3(f,"stz",&p->z,t);
+ }else{
+ do_byte3(f,"lda",&p->q1,t);
+ do_byte3(f,"sta",&p->z,t);
+ }
+ }
+ if(!zmleq(p->q2.val.vmax,l2zm(1L))){
+ if(isreg(z)&&p->z.reg==rax&&!indirect(&p->q1)){
+ do_hibyte(f,"ldx",&p->q1,t);
+ }else if(c2m&&(v&0xFF00)==0){
+ do_hibyte(f,"stz",&p->z,t);
+ }else{
+ load_hibyte(f,&p->q1,t);
+ store_hibyte(f,&p->z,t);
+ }
+ }
+ if(c2m&&(v&0xFF)==0){
+ do_lobyte(f,"stz",&p->z,t);
+ }else{
+ if(isreg(q1)&&ISIDX(p->q1.reg)){
+ store_reg(f,p->q1.reg,&p->z,CHAR);
+ }else if(isreg(z)&&ISIDX(p->z.reg)){
+ load_reg(f,p->z.reg,&p->q1,t);
+ }else{
+ load_lobyte(f,&p->q1,t);
+ store_lobyte(f,&p->z,t);
+ }
+ }
+ }
+ }
+ continue;
+ }
+ if(c==ADDRESS){
+ long o=real_offset(&p->q1);
+ get_acc(f,p,CHAR);
+ emit(f,"\tlda\t%s\n",mregnames[fp1]);
+ if(o){
+ emit(f,"\tclc\n");
+ if((o&255)!=0)
+ emit(f,"\tadc\t#%ld\n",real_offset(&p->q1)&255);
+ }
+ if(isacc(z)){
+ if(o==0) {emit(f,"\tldx\t%s\n",mregnames[fp2]);continue;}
+ if(o==256){emit(f,"\tldx\t%s\n\tinx\n",mregnames[fp2]);continue;}
+ if(o==512){emit(f,"\tldx\t%s\n\tinx\n\tinx\n",mregnames[fp2]);continue;}
+ if(o<256){++label;emit(f,"\tldx\t%s\n\tbcc\t%s%d\n\tinx\n%s%d:\n",mregnames[fp2],labprefix,label,labprefix,label);continue;}
+ if(o<512){++label;emit(f,"\tldx\t%s\n\tinx\n\tbcc\t%s%d\n\tinx\n%s%d:\n",mregnames[fp2],labprefix,label,labprefix,label);continue;}
+ }
+ store_lobyte(f,&p->z,t);
+ if(isacc(z)) emit(f,"\tpha\n");
+ emit(f,"\tlda\t%s\n",mregnames[fp2]);
+ if(o!=0)
+ emit(f,"\tadc\t#%ld\n",real_offset(&p->q1)>>8&255);
+ store_hibyte(f,&p->z,t);
+ if(isacc(z)) emit(f,"\tpla\n");
+ continue;
+ }
+
+ if(c==COMPARE||c==TEST){
+ IC *branch=p->next;
+ int pacc=0,bc,bout;
+ if(ISPOINTER(t)) t|=UNSIGNED;
+ while(branch){
+ if(branch->code>=BEQ&&branch->code<BRA)
+ break;
+ if(branch->code!=FREEREG&&branch->code!=ALLOCREG&&branch->code!=NOP)
+ ierror(0);
+ branch=branch->next;
+ }
+ bc=branch->code;
+ bout=branch->typf;
+ if(c==TEST){
+ p->q2.flags=KONST;
+ gval.vmax=Z0;
+ eval_const(&gval,MAXINT);
+ insert_const(&p->q2.val,t);
+ }
+ if((t&NU)==(UNSIGNED|CHAR)&&(bc==BLE||bc==BGT)&&(p->q2.flags&(DREFOBJ|KONST))==KONST){
+ eval_const(&p->q2.val,t);
+ if(!zmeqto(vmax,l2zm(255L))){
+ vmax=zmadd(vmax,Z1);
+ gval.vmax=vmax;
+ eval_const(&gval,t);
+ insert_const(&p->q2.val,t);
+ if(bc==BLE) bc=BLT; else bc=BGE;
+ branch->code=bc;
+ }
+ }
+ if(((t&NQ)==SHORT||(t&NQ)==INT||(t&NQ)==LONG)&&(bc==BNE||bc==BEQ)&&isconst(q2)&&!isacc(q1)){
+ eval_const(&p->q2.val,t);
+ if(zmeqto(vmax,Z0)&&zumeqto(vumax,ZU0)){
+ if(pacc=cmp_get_acc(f,p,branch))
+ bout=++label;
+ load_lobyte(f,&p->q1,t);
+ do_hibyte(f,"ora",&p->q1,t);
+ if((t&NQ)==LONG){
+ do_byte3(f,"ora",&p->q1,t);
+ do_byte4(f,"ora",&p->q1,t);
+ }
+ emit(f,"\t%s\t%s%d\n",(bc==BNE)?"bne":"beq",labprefix,bout);
+ if(pacc){
+ reload_acc(f);
+ add_cmplist(bout,branch->typf,pacc);
+ }
+ continue;
+ }
+ }
+ if(ieee&&ISFLOAT(t)){
+ if(!ieee) ierror(0);
+ t&=NQ;
+ if(regs[LAST_PAIR]) ierror(0);
+ regs[LAST_PAIR]=1;
+ if(regs[ra]||regs[rax])
+ ierror(0);
+ load_address(f,LAST_PAIR,&p->q2,t);
+ BSET(regused,t3);
+ BSET(regused,t4);
+ emit(f,"\tjsr\t%s__fload%c\n",idprefix,(t==FLOAT?'s':'d'));
+ yval=NOVAL;
+ load_address(f,LAST_PAIR,&p->q1,t);
+ emit(f,"\tjsr\t%s__fcmp%c\n",idprefix,(t==FLOAT?'s':'d'));
+ yval=NOVAL;
+ regs[LAST_PAIR]=0;
+ if(bc==BLT||bc==BLE)
+ emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+ else if(bc==BGT|bc==BGE)
+ emit(f,"\tbvs\t%s%d\n",labprefix,bout);
+ if(bc==BEQ||bc==BLE||bc==BGE)
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ continue;
+ }
+ if(ISCHAR(t)){
+ char *s=0;
+ if(isreg(q1)&&ISIDX(p->q1.reg)&&!indirect(&p->q2)&&(bc==BEQ||bc==BNE||(t&UNSIGNED))){
+ static char buf[4]="cpr";
+ s=buf;s[2]=mregnames[p->q1.reg][0];
+ }else{
+ if(pacc=cmp_get_acc(f,p,branch))
+ bout=++label;
+ load_acc(f,&p->q1,t);
+ if(bc==BEQ||bc==BNE||(t&UNSIGNED)){
+ s="cmp";
+ }else{
+ if(bc==BLT||bc==BGE)
+ emit(f,"\tsec\n");
+ else
+ emit(f,"\tclc\n");
+ s="sbc";
+ }
+ }
+ if(c==TEST)
+ emit(f,"\t%s\t#0\n",s);
+ else
+ do_lobyte(f,s,&p->q2,t);
+ if(bc==BEQ)
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ else if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ else if(t&UNSIGNED){
+ if(bc==BLT)
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ else if(bc==BGE)
+ emit(f,"\tbcs\t%s%d\n",labprefix,bout);
+ else if(bc==BLE){
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ }else if(bc==BGT){
+ emit(f,";\n\tbeq\t%s%d\n",labprefix,++label);
+ emit(f,"\tbcs\t%s%d\n",labprefix,bout);
+ emit(f,"%s%d:\n",labprefix,label);
+ }else
+ ierror(0);
+ }else{
+ emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+ emit(f,"\teor\t#128\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(bc==BLT||bc==BLE)
+ emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+ else
+ emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+ }
+ if(pacc){
+ reload_acc(f);
+ add_cmplist(bout,branch->typf,pacc);
+ }
+ continue;
+ }else if(bc==BEQ||bc==BNE||(t&UNSIGNED)||ISFPOINTER(t)){
+ int in=0;
+ if(pacc=cmp_get_acc(f,p,branch))
+ bout=++label;
+ if(ISLONG(t)){
+ do_byte4(f,"lda",&p->q1,t);
+ if(c==TEST)
+ emit(f,"\tcmp\t#0\n");
+ else
+ do_byte4(f,"cmp",&p->q2,t);
+ if(bc==BEQ)
+ emit(f,"\tbne\t%s%d\n",labprefix,in=++label);
+ else if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ else if(bc==BLT||bc==BLE){
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ emit(f,"\tbne\t%s%d\n",labprefix,in=++label);
+ }else if(bc==BGE||bc==BGT){
+ emit(f,"\tbcc\t%s%d\n",labprefix,in=++label);
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ }else
+ ierror(0);
+ }
+ if(ISLONG(t)||ISFPOINTER(t)){
+ do_byte3(f,"lda",&p->q1,t);
+ if(c==TEST)
+ emit(f,"\tcmp\t#0\n");
+ else
+ do_byte3(f,"cmp",&p->q2,t);
+ if(bc==BEQ)
+ emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+ else if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ else if(bc==BLT||bc==BLE){
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+ }else if(bc==BGE||bc==BGT){
+ emit(f,"\tbcc\t%s%d\n",labprefix,in?in:(in=++label));
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ }else
+ ierror(0);
+ }
+ if(isacc(q1)){
+ if(!indirect(&p->q2)){
+ do_hibyte(f,"cpx",&p->q2,t);
+ }else{
+ int r=get_reg(f,p,CHAR);
+ emit(f,"\tpha\n");
+ load_hibyte(f,&p->q2,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ emit(f,"\tpla\n");
+ emit(f,"\tcpx\t%s\n",mregnames[r]);
+ }
+ }else{
+ load_hibyte(f,&p->q1,t);
+ if(c==TEST)
+ emit(f,"\tcmp\t#0\n");
+ else
+ do_hibyte(f,"cmp",&p->q2,t);
+ }
+ if(bc==BEQ)
+ emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+ else if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ else if(bc==BLT||bc==BLE){
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+ }else if(bc==BGE||bc==BGT){
+ emit(f,"\tbcc\t%s%d\n",labprefix,in?in:(in=++label));
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ }else
+ ierror(0);
+ load_lobyte(f,&p->q1,t);
+ if(c==TEST)
+ emit(f,"\tcmp\t#0\n");
+ else
+ do_lobyte(f,"cmp",&p->q2,t);
+ if(bc==BEQ)
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ else if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ else if(bc==BLT)
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ else if(bc==BGE)
+ emit(f,"\tbcs\t%s%d\n",labprefix,bout);
+ else if(bc==BLE){
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ }else if(bc==BGT){
+ emit(f,"\tbcc\t%s%d\n",labprefix,in);
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ }else
+ ierror(0);
+ if(in)
+ emit(f,"%s%d:\n",labprefix,in);
+ if(pacc){
+ reload_acc(f);
+ add_cmplist(bout,branch->typf,pacc);
+ }
+ continue;
+ }else{
+ if(bc==BGT||bc==BLE){
+ obj o;
+ if(isacc(q1)){
+ int r;
+ if(pacc=cmp_get_acc(f,p,branch))
+ bout=++label;
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ load_lobyte(f,&p->q2,t);
+ emit(f,"\tcmp\t%s\n",mregnames[r]);
+ emit(f,"\tstx\t%s\n",mregnames[r]);
+ load_hibyte(f,&p->q2,t);
+ emit(f,"\tsbc\t%s\n",mregnames[r]);
+ emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+ emit(f,"\teor\t#128\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(bc==BGT)
+ emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+ else
+ emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+ if(pacc){
+ reload_acc(f);
+ add_cmplist(bout,branch->typf,pacc);
+ }
+ continue;
+ }else{
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ if(bc==BGT) bc=BLT; else bc=BGE;
+ }
+ }
+ if(pacc=cmp_get_acc(f,p,branch))
+ bout=++label;
+ if(ISLONG(t)){
+ load_lobyte(f,&p->q1,t);
+ do_lobyte(f,"cmp",&p->q2,t);
+ load_hibyte(f,&p->q1,t);
+ do_hibyte(f,"sbc",&p->q2,t);
+ do_byte3(f,"lda",&p->q1,t);
+ do_byte3(f,"sbc",&p->q2,t);
+ do_byte4(f,"lda",&p->q1,t);
+ do_byte4(f,"sbc",&p->q2,t);
+ }else{
+ load_lobyte(f,&p->q1,t);
+ do_lobyte(f,"cmp",&p->q2,t);
+ load_hibyte(f,&p->q1,t);
+ do_hibyte(f,"sbc",&p->q2,t);
+ }
+ emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+ emit(f,"\teor\t#128\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(bc==BLT)
+ emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+ else if(bc==BGE)
+ emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+ else
+ ierror(0);
+ if(pacc){
+ reload_acc(f);
+ add_cmplist(bout,branch->typf,pacc);
+ }
+ continue;
+ }
+ ierror(0);
+ }
+
+
+ if((c==ADD||c==SUB)&&ISRIDX(z)&&isconst(q2)){
+ eval_const(&p->q2.val,t);
+ if(zmeqto(vmax,l2zm(-1L))){
+ vmax=Z1; vumax=ZU1;
+ if(c==ADD) c=SUB; else c=ADD;
+ }
+ if(zmeqto(vmax,Z1)&&zumeqto(vumax,ZU1)){
+ if(indirect(&p->q1)){
+ get_acc(f,p,CHAR);
+ load_reg(f,p->z.reg,&p->q1,t);
+ }else
+ do_lobyte(f,"ldx",&p->q1,t);
+ emit(f,"\t%s%s\n",(c==ADD)?"in":"de",mregnames[p->z.reg]);
+ continue;
+ }
+ }
+
+ if((c==LSHIFT||c==RSHIFT)&&isconst(q2)&&
+ (
+ (isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg&&p->z.reg!=ra&&p->z.reg!=rax)||
+ (!indirect(&p->q1)&&compare_objects(&p->q1,&p->z))
+ )
+ ){
+ long l;
+ eval_const(&p->q2.val,q2typ(p));
+ l=zm2l(vmax);
+ /*TODO: allow larger types */
+ if((l<3||(iszpage(&p->z)&&l<5))&&(t&NQ)<=LONG){
+ if(c==RSHIFT&&(!c02&&!(t&UNSIGNED)))
+ get_acc(f,p,CHAR);
+ incmem(f,&p->z,t,c,l);
+ continue;
+ }
+ }
+
+ if(c==LSHIFT||c==RSHIFT){
+ long l=-1,m;int loop=0,r=0,r2=0,r3=0,outl=0,same=0;
+ if(isconst(q2)){
+ eval_const(&p->q2.val,q2typ(p));
+ l=zm2l(vmax);
+ loop=0;
+ }else
+ loop=1;
+ if(l>=0&&optsize){
+ if(c==LSHIFT&&(l&7)>6)
+ loop=1;
+ else if(c==RSHIFT&&(t&UNSIGNED)&&(l&7)>3)
+ loop=1;
+ else if(c==RSHIFT&&!(t&UNSIGNED)&&(l&7)>2)
+ loop=1;
+ }
+
+ if(ISLONG(t)){
+ if(!indirect(&p->z)&&
+ (isreg(z)||(p->z.flags&(VAR|DREFOBJ))==VAR)&&
+ (iszpage(&p->z)||(l&7)<=2)&&
+ (!(p->q2.flags®)||!(p->z.flags®)||p->q2.reg!=p->z.reg)&&
+ (!(p->q2.flags&VAR)||!(p->z.flags&VAR)||p->q2.v!=p->z.v)
+ ){
+ if(isreg(z))
+ strcpy(mregnames[REGDUMMY1],mregnames[p->z.reg]);
+ else if(p->z.v->storage_class==STATIC)
+ sprintf(mregnames[REGDUMMY1],"%s%ld",labprefix,zm2l(p->z.v->offset));
+ else
+ sprintf(mregnames[REGDUMMY1],"%s%s",idprefix,p->z.v->identifier);
+ strcpy(mregnames[REGDUMMY2],mregnames[REGDUMMY1]);
+ strcpy(mregnames[REGDUMMY3],mregnames[REGDUMMY1]);
+ strcat(mregnames[REGDUMMY1],"+1");
+ strcat(mregnames[REGDUMMY2],"+2");
+ if(c!=RSHIFT||(t&UNSIGNED))
+ strcat(mregnames[REGDUMMY3],"+3");
+ if(c==RSHIFT&&!(t&UNSIGNED)){
+ r=REGDUMMY2;r2=REGDUMMY1;r3=REGDUMMY3;
+ }else{
+ r=REGDUMMY1;r2=REGDUMMY2;r3=REGDUMMY3;
+ }
+ if(compare_objects(&p->q1,&p->z)) same=1;
+ }else{
+ r2=get_reg(f,p,CHAR);
+ r3=get_reg(f,p,CHAR);
+ }
+ }
+ if(!ISCHAR(t)&&r2!=REGDUMMY1&&r2!=REGDUMMY2)
+ r=get_reg(f,p,CHAR);
+ if(ISLONG(t)){
+ get_acc(f,p,CHAR);
+ if(l>=24){
+ if(c==LSHIFT){
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ emit(f,"\tlda\t#0\n");
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ }else if(c==RSHIFT&&!(t&UNSIGNED)){
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ sety(f,0);
+ emit(f,"\tcmp\t#0\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdey\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tsty\t%s\n",mregnames[r]);
+ emit(f,"\tsty\t%s\n",mregnames[r2]);
+ emit(f,"\ttya\n");
+ yval=NOVAL;
+ }else{
+ do_byte4(f,"lda",&p->q1,t);
+ sety(f,0);
+ emit(f,"\tsty\t%s\n",mregnames[r3]);
+ emit(f,"\tsty\t%s\n",mregnames[r2]);
+ emit(f,"\tsty\t%s\n",mregnames[r]);
+ }
+ }else if(l>=16){
+ if(c==LSHIFT){
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ emit(f,"\tlda\t#0\n");
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ }else if(c==RSHIFT&&!(t&UNSIGNED)){
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ sety(f,0);
+ emit(f,"\tcmp\t#0\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdey\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tsty\t%s\n",mregnames[r]);
+ emit(f,"\ttya\n");
+ yval=NOVAL;
+ }else{
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ do_byte3(f,"lda",&p->q1,t);
+ sety(f,0);
+ emit(f,"\tsty\t%s\n",mregnames[r2]);
+ emit(f,"\tsty\t%s\n",mregnames[r3]);
+ }
+ }else if(l>=8){
+ if(c==LSHIFT){
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ emit(f,"\tlda\t#0\n");
+ }else if(c==RSHIFT&&!(t&UNSIGNED)){
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ sety(f,0);
+ emit(f,"\tcmp\t#0\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdey\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\ttya\n");
+ yval=NOVAL;
+ }else{
+ if(same){
+ load_hibyte(f,&p->q1,t);
+ do_byte3(f,"ldy",&p->q1,t);
+ yval=NOVAL;
+ emit(f,"\tsty\t%s\n",mregnames[r]);
+ do_byte4(f,"ldy",&p->q1,t);
+ emit(f,"\tsty\t%s\n",mregnames[r2]);
+ sety(f,0);
+ emit(f,"\tsty\t%s\n",mregnames[r3]);
+ }else{
+ emit(f,"\tlda\t#0\n");
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ load_hibyte(f,&p->q1,t);
+ }
+ }
+ }else if(c==RSHIFT&&!(t&UNSIGNED)){
+ if(!same){
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ }
+ do_byte4(f,"lda",&p->q1,t);
+ }else{
+ if(!same){
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ }
+ load_lobyte(f,&p->q1,t);
+ }
+ }else
+ get_acc(f,p,t);
+ if(!ISLONG(t)){
+ if(l>=8){
+ if(!ISSHORT(t)) ierror(0);
+ if(c==LSHIFT){
+ if(indirect(&p->q1)){
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\ttax\n");
+ emit(f,"\tlda\t#0\n");
+ }else{
+ if(isacc(q1))
+ emit(f,"\ttax\n");
+ else
+ do_lobyte(f,"ldx",&p->q1,t);
+ emit(f,"\tlda\t#0\n");
+ }
+ }else{
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tldx\t#0\n");
+ if(!(t&UNSIGNED)){
+ emit(f,"\tcmp\t#0\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdex\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }
+ }else
+ load_acc(f,&p->q1,t);
+ }
+ if(l>=0) l&=7;
+ m=l;
+ if(ISSHORT(t)&&(l>0||loop))
+ emit(f,"\tstx\t%s\n",mregnames[r]);
+ if(loop){
+ if(l>=0)
+ sety(f,l);
+ else{
+ if(indirect(&p->q2)){
+ emit(f,"\tpha\n");
+ load_lobyte(f,&p->q2,q2typ(p));
+ emit(f,"\ttay\n");
+ emit(f,"\tpla\n");
+ emit(f,"\tcpy\t#0\n");
+ }else{
+ emit(f,"\tldy\t");
+ emit_lobyte(f,&p->q2,q2typ(p));
+ emit(f,"\n");
+ }
+ outl=++label;
+ emit(f,"\tbeq\t%s%d\n",labprefix,outl);
+ }
+ emit(f,"%s%d:\n",labprefix,++label);
+ }else{
+ if(ISCHAR(t))
+ l&=7;
+ else if(ISSHORT(t))
+ l&=15;
+ else
+ l&=31;
+ }
+ while(l>0||loop){
+ if(c==LSHIFT){
+ emit(f,"\tasl\n");
+ if(!ISCHAR(t))
+ emit(f,"\trol\t%s\n",mregnames[r]);
+ if(ISLONG(t)){
+ emit(f,"\trol\t%s\n",mregnames[r2]);
+ emit(f,"\trol\t%s\n",mregnames[r3]);
+ }
+ }else if(t&UNSIGNED){
+ emit(f,"\tlsr");
+ if(ISLONG(t)){
+ emit(f,"\t%s\n",mregnames[r3]);
+ emit(f,"\tror\t%s\n",mregnames[r2]);
+ emit(f,"\tror");
+ }
+ if(!ISCHAR(t)){
+ emit(f,"\t%s\n",mregnames[r]);
+ emit(f,"\tror");
+ }
+ emit(f,"\n");
+ }else{
+ if(ISLONG(t)){
+ if(ce02)
+ emit(f,"\tasr\n");
+ else{
+ emit(f,"\tcmp\t#128\n");
+ emit(f,"\tror\n");
+ }
+ emit(f,"\tror\t%s\n",mregnames[r]);
+ emit(f,"\tror\t%s\n",mregnames[r2]);
+ emit(f,"\tror\t%s\n",mregnames[r3]);
+ }else{
+ if(!ISCHAR(t)){
+ emit(f,"\tcpx\t#128\n");
+ emit(f,"\tror\t%s\n",mregnames[r]);
+ }else
+ emit(f,"\tcmp\t#128\n");
+ emit(f,"\tror\n");
+ }
+ }
+ if(loop){
+ emit(f,"\tdey\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,label);
+ if(outl) emit(f,"%s%d:\n",labprefix,outl);
+ yval=0;
+ break;
+ }
+ l--;
+ }
+ if(ISLONG(t)){
+ if(c==RSHIFT&&!(t&UNSIGNED)){
+ do_byte4(f,"sta",&p->z,t);
+ if(r!=REGDUMMY2){
+ emit(f,"\tlda\t%s\n",mregnames[r]);
+ do_byte3(f,"sta",&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r2]);
+ store_hibyte(f,&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r3]);
+ store_lobyte(f,&p->z,t);
+ }
+ }else{
+ store_lobyte(f,&p->z,t);
+ if(r!=REGDUMMY1){
+ emit(f,"\tlda\t%s\n",mregnames[r]);
+ store_hibyte(f,&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r2]);
+ do_byte3(f,"sta",&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r3]);
+ do_byte4(f,"sta",&p->z,t);
+ }
+ }
+ }else{
+ if(!ISCHAR(t)&&(m>0||loop))
+ emit(f,"\tldx\t%s\n",mregnames[r]);
+ if(ISCHAR(t)||indirect(&p->z))
+ store_acc(f,&p->z,t);
+ else{
+ store_lobyte(f,&p->z,t);
+ if(!isreg(z)||p->z.reg!=rax){
+ emit(f,"\tstx\t");
+ emit_hibyte(f,&p->z,t);
+ emit(f,"\n");
+ }
+ }
+ }
+ continue;
+ }
+
+ if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)||c==ADDI2P||c==SUBIFP){
+ char *s;int t2=t,pt=p->typf2;
+ if(!isacc(z)){
+ /* TODO: check other operations */
+ if((c==ADD||c==SUB||c==AND||c==XOR||c==OR||c==ADDI2P||c==SUBIFP)&&isacc(q1)&&scratch(p->next,ra,1))
+ ;
+ else{
+ if((c==ADDI2P||c==SUBIFP)&&(p->typf2&NU)==CHAR)
+ get_acc(f,p,INT);
+ else
+ get_acc(f,p,CHAR);
+ }
+ }
+ if(c==ADDI2P||c==SUBIFP){
+ if(c==ADDI2P) c=ADD; else c=SUB;
+ t=UNSIGNED|INT;
+ if((pt&NQ)==POINTER&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q1.val,POINTER);
+ insert_const(&p->q1.val,UNSIGNED|INT);
+ }
+ }
+ if(c>=OR&&c<=AND)
+ s=logicals[c-OR];
+ else
+ s=arithmetics[c-LSHIFT];
+
+ if(ISFLOAT(t)){
+ if(!ieee) ierror(0);
+ t&=NQ;
+ if(regs[LAST_PAIR]) ierror(0);
+ get_acc(f,p,INT);
+ regs[LAST_PAIR]=1;
+ load_address(f,LAST_PAIR,&p->q1,t);
+ BSET(regused,t3);
+ BSET(regused,t4);
+ emit(f,"\tjsr\t%s__fload%c\n",idprefix,(t==FLOAT?'s':'d'));
+ yval=NOVAL;
+ load_address(f,LAST_PAIR,&p->q2,t);
+ emit(f,"\tjsr\t%s__f%s%c\n",idprefix,ename[c],(t==FLOAT?'s':'d'));
+ yval=NOVAL;
+ load_address(f,LAST_PAIR,&p->z,t);
+ emit(f,"\tjsr\t%s__fstore%c\n",idprefix,(t==FLOAT?'s':'d'));
+ yval=NOVAL;
+ regs[LAST_PAIR]=0;
+ continue;
+ }else if(ISLONG(t)){
+ long l;int cnst=0;
+ if(c==ADD) emit(f,"\tclc\n");
+ if(c==SUB) emit(f,"\tsec\n");
+ if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,t);
+ l=zm2l(vmax);
+ cnst=1;
+ }
+ if(cnst&&c==AND&&(l&0xff)==0) emit(f,"\tlda\t#0\n");
+ else if(cnst&&c==OR&&(l&0xff)==0xff) emit(f,"\tlda\t#255\n");
+ else{
+ load_lobyte(f,&p->q1,t);
+ if(!(cnst&&((c==AND&&(l&0xff)==0xff)||(c==OR&&(l&0xff)==0)||(c==XOR&&(l&0xff)==0)))) do_lobyte(f,s,&p->q2,t);
+ }
+ store_lobyte(f,&p->z,t);
+ if(cnst&&c==AND&&(l&0xff00)==0) emit(f,"\tlda\t#0\n");
+ else if(cnst&&c==OR&&(l&0xff00)==0xff00) emit(f,"\tlda\t#255\n");
+ else{
+ load_hibyte(f,&p->q1,t);
+ if(!(cnst&&((c==AND&&(l&0xff00)==0xff00)||(c==OR&&(l&0xff00)==0)||(c==XOR&&(l&0xff00)==0)))) do_hibyte(f,s,&p->q2,t);
+ }
+ store_hibyte(f,&p->z,t);
+ if(cnst&&c==AND&&(l&0xff0000)==0) emit(f,"\tlda\t#0\n");
+ else if(cnst&&c==OR&&(l&0xff0000)==0xff0000) emit(f,"\tlda\t#255\n");
+ else{
+ do_byte3(f,"lda",&p->q1,t);
+ if(!(cnst&&((c==AND&&(l&0xff0000)==0xff0000)||(c==OR&&(l&0xff0000)==0)||(c==XOR&&(l&0xff0000)==0)))) do_byte3(f,s,&p->q2,t);
+ }
+ do_byte3(f,"sta",&p->z,t);
+ if(cnst&&c==AND&&(l&0xff000000)==0) emit(f,"\tlda\t#0\n");
+ else if(cnst&&c==OR&&(l&0xff000000)==0xff000000) emit(f,"\tlda\t#255\n");
+ else{
+ do_byte4(f,"lda",&p->q1,t);
+ if(!(cnst&&((c==AND&&(l&0xff000000)==0xff000000)||(c==OR&&(l&0xff000000)==0)||(c==XOR&&(l&0xff000000)==0)))) do_byte4(f,s,&p->q2,t);
+ }
+ do_byte4(f,"sta",&p->z,t);
+ continue;
+ }else if(ISCHAR(t)){
+ load_acc(f,&p->q1,t);
+ if(c02&&(c==ADD||c==SUB)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,t);
+ if(zmeqto(vmax,Z1)||zmeqto(vmax,l2zm(2L))){
+ if(zmeqto(vmax,l2zm(2L)))
+ emit(f,"\t%s\n",c==ADD?"ina":"dea");
+ emit(f,"\t%s\n",c==ADD?"ina":"dea");
+ store_acc(f,&p->z,t);
+ continue;
+ }
+ }
+ if(c==ADD) emit(f,"\tclc\n");
+ if(c==SUB) emit(f,"\tsec\n");
+ if(isreg(q2)&&ISIDX(p->q2.reg)){
+ int r=get_reg(f,p,CHAR);
+ emit(f,"\tst%s\t%s\n",mregnames[p->q2.reg],mregnames[r]);
+ p->q2.flags=REG;
+ p->q2.reg=r;
+ }
+ do_lobyte(f,s,&p->q2,t);
+ store_acc(f,&p->z,t);
+ }else if(c==ADD||c==SUB){
+ int a,r;long l=1;
+ if(isconst(q2)){
+ eval_const(&p->q2.val,t2);
+ l=zm2l(vmax);
+ if(isacc(z)&&(l&0xffff)<=768){
+ load_acc(f,&p->q1,t);
+ if(c==ADD){
+ if(l&0xff)
+ emit(f,"\tclc\n\tadc\t#%d\n",(int)(l&255));
+ l&=0xffff;
+ if(l==256){emit(f,"\tinx\n");continue;}
+ if(l==512){emit(f,"\tinx\n\tinx\n");continue;}
+ if(l==768){emit(f,"\tinx\n\tinx\n\tinx\n");continue;}
+ if(l<256){++label;emit(f,"\tbcc\t%s%d\n\tinx\n%s%d:\n",labprefix,label,labprefix,label);continue;}
+ if(l<512){++label;emit(f,"\tinx\n\tbcc\t%s%d\n\tinx\n%s%d:\n",labprefix,label,labprefix,label);continue;}
+ if(l<768){++label;emit(f,"\tinx\n\tinx\n\tbcc\t%s%d\n\tinx\n%s%d:\n",labprefix,label,labprefix,label);continue;}
+ }else{
+ if(l&0xff)
+ emit(f,"\tsec\n\tsbc\t#%d\n",(int)(l&255));
+ l&=0xffff;
+ if(l==256){emit(f,"\tdex\n");continue;}
+ if(l==512){emit(f,"\tdex\n\tdex\n");continue;}
+ if(l==768){emit(f,"\tdex\n\tdex\n\tdex\n");continue;}
+ if(l<256){++label;emit(f,"\tbcs\t%s%d\n\tdex\n%s%d:\n",labprefix,label,labprefix,label);continue;}
+ if(l<512){++label;emit(f,"\tdex\n\tbcs\t%s%d\n\tdex\n%s%d:\n",labprefix,label,labprefix,label);continue;}
+ if(l<768){++label;emit(f,"\tdex\n\tdex\n\tbcs\t%s%d\n\tdex\n%s%d:\n",labprefix,label,labprefix,label);continue;}
+ }
+ }
+ l&=0xff00;
+ }
+ if(isreg(z)&&p->z.reg==rax) a=1; else a=0;
+ if((t2&NU)==CHAR&&(p->q2.flags&(KONST|DREFOBJ))!=KONST){
+ get_acc(f,p,INT);
+ emit(f,"\tldx\t#0\n");
+ load_lobyte(f,&p->q2,t);
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdex\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(c==ADD){
+ if(c==ADD) emit(f,"\tclc\n"); else emit(f,"\tsec\n");
+ do_lobyte(f,s,&p->q1,t);
+ if(isacc(z))
+ emit(f,"\tpha\n");
+ else
+ store_lobyte(f,&p->z,t);
+ emit(f,"\ttxa\n");
+ do_hibyte(f,s,&p->q1,t);
+ store_hibyte(f,&p->z,t);
+ if(ISFPOINTER(pt)&&!compare_objects(&p->q1,&p->z)){
+ do_byte3(f,"lda",&p->q1,pt);
+ do_byte3(f,"sta",&p->z,pt);
+ }
+ if(isacc(z))
+ emit(f,"\tpla\n");
+ continue;
+ }
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tstx\t%s\n",mregnames[r]);
+ }
+ load_lobyte(f,&p->q1,t);
+ if(c==ADD) emit(f,"\tclc\n"); else emit(f,"\tsec\n");
+ do_lobyte(f,s,&p->q2,t2);
+ store_lobyte(f,&p->z,t);
+ if(l==0&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg){
+ if(c==ADD){
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ if(a)
+ emit(f,"\tinx\n");
+ else{
+ /*if(!reg_pair(p->z.reg,&rp)) ierror(0);*/
+ emit(f,"\tinc\t%s+1\n",mregnames[p->z.reg]);
+ }
+ }else{
+ emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+ if(a)
+ emit(f,"\tdex\n");
+ else{
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ emit(f,"\tdec\t%s\n",mregnames[rp.r2]);
+ }
+ }
+ emit(f,"%s%d:\n",labprefix,label);
+ }else{
+ if(a==1) emit(f,"\tpha\n");
+ if((t2&NQ)==CHAR){
+ if(t2&UNSIGNED){
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\t%s\t#0\n",s);
+ }else{
+ load_hibyte(f,&p->q1,t);
+ if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,t2);
+ if(zmleq(Z0,vmax))
+ emit(f,"\t%s\t#0\n",s);
+ else
+ emit(f,"\t%s\t#255\n",s);
+ }else{
+ emit(f,"\t%s\t%s\n",s,mregnames[r]);
+ }
+ }
+ }else{
+ load_hibyte(f,&p->q1,t);
+ do_hibyte(f,s,&p->q2,t2);
+ }
+ store_hibyte(f,&p->z,t);
+ if(a==1) emit(f,"\tpla\n");
+ if(ISFPOINTER(pt)&&p->code!=SUBPFP){
+ if(!compare_objects(&p->q1,&p->z)){
+ do_byte3(f,"lda",&p->q1,FPOINTER);
+ do_byte3(f,"sta",&p->z,FPOINTER);
+ }
+ }
+ }
+ }else{
+ long l=-1;int dello=0;
+ if(c!=AND&&c!=OR&&c!=XOR) ierror(0);
+ if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,t);
+ l=zm2l(vmax)&0xffff;
+ }
+ if(l>0&&((c==AND&&(l&0xFF)==0)||(c==OR&&(l&0xFF)==0xFF))){
+ dello=1;
+ }else if(l>0&&((c==AND&&(l&0xFF)==0xFF)||((c==OR||c==XOR)&&(l&0xFF)==0))){
+ if(!compare_objects(&p->q1,&p->z)){
+ load_lobyte(f,&p->q1,t);
+ store_lobyte(f,&p->z,t);
+ }
+ }else{
+ load_lobyte(f,&p->q1,t);
+ do_lobyte(f,s,&p->q2,t);
+ store_lobyte(f,&p->z,t);
+ }
+ if(l>0&&((c==AND&&(l&0xFF00)==0)||(c==OR&&(l&0xFF00)==0xFF00))){
+ int val=(c==AND)?0:255;
+ if(isacc(z)){
+ emit(f,"\tldx\t#%d\n",val);
+ }else{
+ emit(f,"\tlda\t#%d\n",val);
+ store_hibyte(f,&p->z,t);
+ }
+ }else if(l>0&&((c==AND&&(l&0xFF00)==0xFF00)||((c==OR||c==XOR)&&(l&0xFF00)==0))){
+ if(isacc(z)&&!indirect(&p->q1)){
+ do_hibyte(f,"ldx",&p->q1,t);
+ }else{
+ if(!compare_objects(&p->q1,&p->z)){
+ if(!dello&&isacc(z))
+ emit(f,"\tpha\n");
+ load_hibyte(f,&p->q1,t);
+ store_hibyte(f,&p->z,t);
+ if(!dello&&isacc(z))
+ emit(f,"\tpla\n");
+ }
+ }
+ }else{
+ if(!dello&&isacc(z))
+ emit(f,"\tpha\n");
+ load_hibyte(f,&p->q1,t);
+ do_hibyte(f,s,&p->q2,t);
+ store_hibyte(f,&p->z,t);
+ if(!dello&&isacc(z))
+ emit(f,"\tpla\n");
+ }
+ if(dello){
+ emit(f,"\tlda\t#%d\n",(c==AND)?0:255);
+ store_lobyte(f,&p->z,t);
+ }
+ }
+ continue;
+ }
+ pric2(stdout,p);
+ ierror(0);
+ }
+
+ function_bottom(f,v,localsize);
+
+ for(c=1;c<=MAXR;c++){
+ if(regsa[c]||regused[c]){
+ BSET(regs_modified,c);
+ }
+ }
+
+ if(stack_valid){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=stack;
+ }
+ }
+
+ free_IC(mi);
+
+ emit(f,"; stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int code,int typ)
+{
+ if(code==COMPARE||code==MULT||code==ADD||code==SUB||code==AND||code==OR||code==XOR||code==LSHIFT||code==RSHIFT||code==MINUS||code==KOMPLEMENT||code==NEGATION)
+ return 1;
+
+ return 0;
+}
+
+static int fattr(type *p,char *s)
+{
+ if(p->attr&&strstr(p->attr,s))
+ return 1;
+ if(p->next)
+ return fattr(p->next,s);
+ else
+ return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+ int f;
+
+ if(vararg)
+ return 0;
+ f=t->flags&NQ;
+ if(OLDFP&&ISFLOAT(f)) return 0;
+ if(d&&fattr(d,"__stackparms__"))
+ return 0;
+ if(d&&fattr(d,"__cc65__")){
+ m->regs++;
+ printf("arg=%d cnt=%d\n",m->regs,d->exact->count);
+ if(m->regs==d->exact->count-1){
+ if(ISCHAR(t->flags))
+ return ra;
+ if(ISSHORT(t->flags))
+ return rax;
+ }
+ return 0;
+ }
+ if(ISCHAR(f)){
+ if(!t->exact){
+ if(m->regs>=GPR_ARGS-1)
+ return 0;
+ f=FIRST_GPR+m->regs;
+ m->regs+=2;
+ return f;
+ }else{
+ if(m->regs>=GPR_ARGS)
+ return 0;
+ else
+ return FIRST_GPR+m->regs++;
+ }
+ }
+ if(ISSHORT(f)||f==POINTER){
+ if(m->regs>=GPR_ARGS-1)
+ return 0;
+ else{
+ if(m->regs&1) m->regs+=1;
+ m->regs+=2;
+ return FIRST_PAIR+m->regs/2-1;
+ }
+ }
+ if(f==FPOINTER||f==LONG||f==FLOAT||(!ieee&&(f==DOUBLE||f==LDOUBLE))){
+ if(m->bregs>=4)
+ return 0;
+ else
+ return FIRST_BIG+m->bregs++;
+ }
+ if(f==LLONG||(ieee&&(f==DOUBLE||f==LDOUBLE))){
+ if(m->bregs>=3)
+ return 0;
+ else{
+ if(m->bregs&1) m->bregs++;
+ m->bregs+=2;
+ return FIRST_BIGP+m->bregs/2-1;
+ }
+ }
+ return 0;
+}
+
+int handle_pragma(const char *s)
+{
+ static char sec[SECLEN];
+ int i;
+ if(sscanf(s,"section %127s",sec)==1){
+ if(!strcmp(sec,"default"))
+ use_sec=0;
+ else
+ use_sec=sec;
+ return 1;
+ }
+ if(sscanf(s,"bank %d",&i)==1){
+ use_bank=i;
+ return 1;
+ }
+}
+void cleanup_cg(FILE *f)
+{
+ int i;
+ struct fpconstlist *p=firstfpc;
+
+ if(f&&p){
+ emit(f,rodataname);emit(f,"\n");
+ section=RODATA;
+ }
+ while(p=firstfpc){
+ emit(f,"%s%d:\n\tword\t",labprefix,p->label);
+ if(ieee)
+ emit_ieee(f,&p->val,p->t);
+ else{
+ int words=zm2l(sizetab[p->t&NQ])/2;
+ eval_const(&p->val,p->t);
+ if(ISFLOAT(p->t)) cnv_fp();
+ for(i=0;i<words;i++){
+ emit(f,"%ld",zm2l(vmax)&0xffff);
+ if(i<words-1){emit(f,",");vmax=zmrshift(vmax,l2zm(16L));}
+ }
+ emit(f,"\n");
+ /*emit(f,"%ld,%ld\n",zm2l(vmax)&0xffff,zm2l(zmrshift(vmax,l2zm(16L)))&0xffff);*/
+ }
+ firstfpc=p->next;
+ free(p);
+ }
+
+ emit(f,"\tzpage\t%s\n",mregnames[sp]);
+ for(i=FIRST_GPR;i<=LAST_GPR;i++)
+ emit(f,"\tzpage\t%s\n",mregnames[i]);
+ for(i=FIRST_BIG;i<=LAST_BIG;i++)
+ emit(f,"\tzpage\t%s\n",mregnames[i]);
+
+}
+void cleanup_db(FILE *f)
+{
+ if(f) section=-1;
+}
+
+static char *zops[]={
+ "adc","and","asl","bit","eor","lda","ora",
+ "tax","txa","tay","tya","sbc"};
+
+static int setszflag(char *op)
+{
+ int i;
+ for(i=0;i<sizeof(zops)/sizeof(zops[0]);i++)
+ if(!strcmp(op,zops[i]))
+ return 1;
+ return 0;
+}
+
+static char *zxops[]={
+ "tax","txa","ldx","inx","dex"};
+
+static int setszxflag(char *op)
+{
+ int i;
+ for(i=0;i<sizeof(zxops)/sizeof(zxops[0]);i++)
+ if(!strcmp(op,zxops[i]))
+ return 1;
+ return 0;
+}
+
+enum peepf { NEEDSAME = 1, REMOVE1ST = 2};
+struct peeps {char *s1,*s2,*r;enum peepf flags;};
+
+
+
+int emit_peephole(void)
+{
+ int entries,i,j;
+ char *asmline[EMIT_BUF_DEPTH];
+ char buf1[1024],buf2[1024];
+ char op1[8],op2[8];
+ static char ca[1024],cx[1024],cy[1024],cz[1024];
+ static int rm,disabled;
+
+ static struct peeps elim[]={
+ "lda","sta",0,NEEDSAME,
+ "ldx","stx",0,NEEDSAME,
+ "ldy","sty",0,NEEDSAME,
+ "ldz","stz",0,NEEDSAME,
+ "ldq","stq",0,NEEDSAME,
+ "sta","sta",0,NEEDSAME,
+ "stx","stx",0,NEEDSAME,
+ "sty","sty",0,NEEDSAME,
+ "stz","stz",0,NEEDSAME,
+ "stq","stq",0,NEEDSAME,
+ "sta","lda",0,NEEDSAME,
+ "stx","ldx",0,NEEDSAME,
+ "sty","ldy",0,NEEDSAME,
+ "stz","ldz",0,NEEDSAME,
+ "stq","ldq",0,NEEDSAME,
+ "txa","tax",0,0,
+ "tax","txa",0,0,
+ "tay","tya",0,0,
+ "tya","tay",0,0,
+ "tza","taz",0,0,
+ "taz","tza",0,0,
+ "lda","lda",0,REMOVE1ST,
+ "ldx","ldx",0,REMOVE1ST,
+ "ldy","ldy",0,REMOVE1ST,
+ "ldz","ldz",0,REMOVE1ST,
+ "ldq","ldq",0,REMOVE1ST,
+ "lda","ldq",0,REMOVE1ST,
+ "ldx","ldq",0,REMOVE1ST,
+ "ldy","ldq",0,REMOVE1ST,
+ "lda","pla",0,REMOVE1ST,
+ "ldx","plx",0,REMOVE1ST,
+ "ldy","ply",0,REMOVE1ST,
+ "ldz","plz",0,REMOVE1ST,
+ "lda","txa",0,REMOVE1ST,
+ "lda","tya",0,REMOVE1ST,
+ "lda","tza",0,REMOVE1ST,
+ "ldx","tax",0,REMOVE1ST,
+ "ldy","tay",0,REMOVE1ST,
+ "ldz","taz",0,REMOVE1ST,
+ "tay","ldy",0,REMOVE1ST,
+ "tax","ldx",0,REMOVE1ST,
+ "taz","ldz",0,REMOVE1ST,
+ "txa","lda",0,REMOVE1ST,
+ "tya","lda",0,REMOVE1ST,
+ "tza","lda",0,REMOVE1ST,
+ "lda","ldx","\ttax\n",NEEDSAME,
+ "lda","ldy","\ttay\n",NEEDSAME,
+ "lda","ldz","\ttaz\n",NEEDSAME,
+ "ldx","lda","\ttxa\n",NEEDSAME,
+ "ldy","lda","\ttya\n",NEEDSAME,
+ "ldz","lda","\ttza\n",NEEDSAME,
+ "sta","ldx","\ttax\n",NEEDSAME,
+ "sta","ldy","\ttay\n",NEEDSAME,
+ "sta","ldz","\ttaz\n",NEEDSAME,
+ "stx","lda","\ttxa\n",NEEDSAME,
+ "sty","lda","\ttya\n",NEEDSAME,
+ "stz","lda","\ttza\n",NEEDSAME, /* must be last */
+ };
+
+ if(nopeep) return 0;
+
+ /* activate optimization that is not valid for c02 */
+ if(!ce02) elim[sizeof(elim)/sizeof(elim[0])-1].r="\tlda\t#0\n";
+
+ i=emit_l;
+ if(emit_f==0)
+ entries=i-emit_f+1;
+ else
+ entries=EMIT_BUF_DEPTH;
+ asmline[0]=emit_buffer[i];
+
+ if(!strcmp(asmline[0],";startinline\n")) disabled=1;
+ if(!strcmp(asmline[0],";endinline\n")) disabled=0;
+ if(disabled) return 0;
+
+ buf1[0]=0;op1[0]=0;
+ if((j=sscanf(asmline[0]," %6s %999s",op1,buf1))>=1){
+ /*printf("a=%s x=%s y=%s z=%s\n",ca,cx,cy,cz);
+ printf("\t\t%s %s\n",op1,buf1);*/
+ if(!strcmp(op1,"lda")){
+ if(buf1[0]=='#'){
+ if(!rm&&!strcmp(buf1,ca)){remove_asm();return rm=1;}
+ if(!rm&&!strcmp(buf1,cx)){strcpy(asmline[0],"\ttxa\n");return rm=1;}
+ if(!rm&&!strcmp(buf1,cy)){strcpy(asmline[0],"\ttya\n");return rm=1;}
+ if(!rm&&!strcmp(buf1,cz)){strcpy(asmline[0],"\ttza\n");return rm=1;}
+ strcpy(ca,buf1);
+ }else ca[0]=0;
+ }else if(!strcmp(op1,"ldx")){
+ if(buf1[0]=='#'){
+ if(!rm&&!strcmp(buf1,cx)){remove_asm();return rm=1;}
+ if(!rm&&!strcmp(buf1,ca)){strcpy(asmline[0],"\ttax\n");return rm=1;}
+ strcpy(cx,buf1);
+ }else cx[0]=0;
+ }else if(!strcmp(op1,"ldy")){
+ if(buf1[0]=='#'){
+ if(!rm&&!strcmp(buf1,cy)){remove_asm();return rm=1;}
+ if(!rm&&!strcmp(buf1,ca)){strcpy(asmline[0],"\ttay\n");return rm=1;}
+ strcpy(cy,buf1);
+ }else cy[0]=0;
+ }else if(!strcmp(op1,"ldz")){
+ if(buf1[0]=='#'){
+ if(!rm&&!strcmp(buf1,cz)){remove_asm();return rm=1;}
+ if(!rm&&!strcmp(buf1,ca)){strcpy(asmline[0],"\ttaz\n");return rm=1;}
+ strcpy(cz,buf1);
+ }else cz[0]=0;
+ }else{
+ static char clobbernone[]="asw bit clc cld cli clv cmp cpx cpy dec deq dew inc inq inw nop pha php phw phz plp sec sed sei sta stq stx sty";
+ static char clobbera[]="adc and asl asr eor lsr ora pla rol ror sbc txa tya tza";
+ static char clobberx[]="dex inx tax tsx";
+ static char clobbery[]="dey iny tay";
+ static char clobberz[]="dez inz taz";
+ if(strstr(clobbernone,op1)){
+ }else if(strstr(clobbera,op1))
+ ca[0]=0;
+ else if(strstr(clobberx,op1))
+ cx[0]=0;
+ else if(strstr(clobbery,op1))
+ cy[0]=0;
+ else if(strstr(clobberz,op1))
+ cz[0]=0;
+ else
+ ca[0]=cx[0]=cy[0]=cz[0]=0;
+ }
+ }else{
+ ca[0]=cx[0]=cy[0]=cz[0]=0;
+ }
+
+ rm=0;
+
+ if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"and")&&!strcmp(buf1,"#0")){
+ strcpy(asmline[0],"\tlda\t#0\n");
+ return rm=1;
+ }
+
+ if(entries>=2){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[1]=emit_buffer[i];
+
+
+ if(!strcmp(asmline[0],"; volatile barrier\n")&&!strcmp(asmline[0],asmline[1])){
+ remove_asm();
+ return rm=1;
+ }
+
+ if(sscanf(asmline[0]," %6s",op1)==1&&!strcmp(op1,"rts")&&
+ sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&!strcmp(op2,"jsr")){
+ sprintf(asmline[1],"\tjmp\t%s\n",buf2);
+ remove_asm();
+ return rm=1;
+ }
+
+ for(j=0;j<sizeof(elim)/sizeof(elim[0]);j++){
+ if(elim[j].flags&NEEDSAME){
+ if(sscanf(asmline[0]," %6s %999s",op2,buf2)==2&&
+ sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&
+ !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)&&
+ !strcmp(buf1,buf2)){
+ if(elim[j].r){
+ strcpy(asmline[0],elim[j].r);
+ }else{
+ if(elim[j].flags&REMOVE1ST)
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ }
+ return rm=1;
+ }
+ }else{
+ if(sscanf(asmline[1]," %6s",op1)==1&&
+ sscanf(asmline[0]," %6s",op2)==1&&
+ !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)){
+ if(elim[j].flags&REMOVE1ST)
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return rm=1;
+ }
+ }
+ }
+
+
+ }
+
+ if(entries>=3){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[2]=emit_buffer[i];
+ if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2){
+#if 0
+ if(!strcmp(op1,"lda")&&buf1[0]=='#'){
+ if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+ !strcmp(op2,"sta")){
+ if(sscanf(asmline[2]," %6s %999s",op2,buf2)==2&&
+ !strcmp(op2,"lda")&&!strcmp(buf1,buf2)){
+ remove_asm();
+ return rm=1;
+ }
+ }
+ }
+#endif
+ if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){
+ if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+ !strcmp(op2,"cmp")&&!strcmp(buf2,"#0")){
+ if(sscanf(asmline[2]," %6s",op2)==1&&
+ setszflag(op2)){
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return rm=1;
+ }
+ }
+ }
+ if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){
+ if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+ !strcmp(op2,"cpx")&&!strcmp(buf2,"#0")){
+ if(sscanf(asmline[2]," %6s",op2)==1&&
+ setszxflag(op2)){
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return rm=1;
+ }
+ }
+ }
+ }
+ }
+ if(entries>=4){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[3]=emit_buffer[i];
+ }
+ if(entries>=5){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[4]=emit_buffer[i];
+ if(sscanf(asmline[0]," %s %s",op1,buf1)>=1){
+ if(!strcmp(op1,"lda")||!strcmp(op1,"pla")||!strcmp(op1,"txa")||!strcmp(op1,"tya")){
+ if(sscanf(asmline[1]," %s %s",op1,buf1)>=1&&!strcmp(op1,"pla")&&
+ sscanf(asmline[2]," %s %s",op1,buf1)>=1&&!strcmp(op1,"tay")&&
+ sscanf(asmline[3]," %s %s",op1,buf1)>=1&&!strcmp(op1,"txa")&&
+ sscanf(asmline[4]," %s %s",op1,buf1)>=1&&!strcmp(op1,"pha")){
+ strcpy(asmline[4],asmline[3]);
+ strcpy(asmline[3],asmline[2]);
+ strcpy(asmline[2],asmline[0]);
+ remove_asm();
+ remove_asm();
+ return rm=1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/* Return name of library function, if this node should be
+ implemented via libcall. */
+char *use_libcall(int c,int t,int t2)
+{
+ static char fname[16];
+ char *ret=0;
+
+ if(c==COMPARE){
+ if((t&NQ)==LLONG||(ISFLOAT(t)&&!ieee)){
+ sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }else{
+ t&=NU;
+ t2&=NU;
+ if(ISSHORT(t)&&c!=MULT&&c!=DIV&&c!=MOD&&!ISFLOAT(t2))
+ return 0;
+ if(ISLONG(t)&&c!=MULT&&c!=DIV&&c!=MOD&&!ISFLOAT(t2))
+ return 0;
+
+ if(!ieee&&ISFLOAT(t)) t=FLOAT;
+ if(t==LDOUBLE) t=DOUBLE;
+ if(t2==LDOUBLE) t2=DOUBLE;
+ if(!ieee&&ISFLOAT(t2)) t2=FLOAT;
+ if(c==CONVERT){
+ if(t==t2) return 0;
+ if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+ if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+
+ if(ISFLOAT(t)){
+ sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64);
+ ret=fname;
+ }
+ if(ISFLOAT(t2)){
+ sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+ if(c==MULT&&(t&NQ)==CHAR&&!m65) return "__mulint8";
+ if((t&NQ)==SHORT||(t&NQ)==INT||(t&NQ)==LONG||(t&NQ)==LLONG||(!ieee&&ISFLOAT(t))){
+ if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+ if(m65&&ISLONG(t)&&(c==MULT||(c==DIV&&!divbug&&(t&UNSIGNED)))) return 0;
+ if(m65&&c==MULT&&ISSHORT(t)) return 0;
+ if(t==(UNSIGNED|LLONG)&&(c==MULT||c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint64",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==LLONG){
+ sprintf(fname,"__%sint64",ename[c]);
+ ret=fname;
+ }else if(t==(UNSIGNED|LONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint32",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==LONG){
+ sprintf(fname,"__%sint32",ename[c]);
+ ret=fname;
+ }else if(t==(UNSIGNED|INT)&&(c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint16",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==INT){
+ sprintf(fname,"__%sint16",ename[c]);
+ ret=fname;
+ }else{
+ sprintf(fname,"__%s%s%s%ld",ename[c],(t&UNSIGNED)?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+ }
+ }
+
+ if(ret&&divbug&&(c==DIV||c==MOD)&&!ISFLOAT(t)) strcat(ret,"wo");
+
+ return ret;
+}
+
+
+int pointer_varadr(Var *v)
+{
+ int b=bank(v);
+ if(b>=0&&b!=bankcnum&&!NOBANKVARS){
+ if(cur_funcv&&bank(cur_funcv)!=b)
+ return FPOINTER;
+ }
+ return pointer_type(v->vtyp);
+}
+
+int pointer_type(struct Typ *p)
+{
+ struct Typ *merk=p;
+ if(!p) ierror(0);
+ if(LARGE) return FPOINTER;
+ while(ISARRAY(p->flags)||ISFUNC(p->flags)) p=p->next;
+ if(p->attr){
+ char *s;
+ if(strstr(p->attr,STR_HUGE)) return HPOINTER;
+ if(strstr(p->attr,STR_FAR)) return FPOINTER;
+ if(strstr(p->attr,STR_NEAR)) return POINTER;
+ }
+ return POINTER;
+}
+
+unsigned char cbmconv(unsigned char x)
+{
+ static unsigned char ctab[256]={
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x14,0x09,0x0D,0x11,0x93,0x0A,0x0E,0x0F,
+ 0x10,0x0B,0x12,0x13,0x08,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+ 0x40,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0x5B,0xBF,0x5D,0x5E,0xA4,
+ 0xAD,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0xB3,0xDD,0xAB,0xB1,0xDF,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+ 0x90,0x91,0x92,0x0C,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+ 0xA0,0xA1,0xA2,0xA3,0x5F,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0x7D,0xAC,0x60,0xAE,0xAF,
+ 0xB0,0x7E,0xB2,0x7B,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0x5C,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0xDC,0x7C,0xDE,0x7F,
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+ };
+
+ static unsigned char atab[]={0xfd,8,0x7f,0x9b,11,0x7d};
+
+ if(cbmascii)
+ return ctab[x&255];
+ else if(atascii&&x>=7&&x<=12)
+ return atab[x-7];
+ else
+ return x;
+}
+
+void insert_const(union atyps *p,int t)
+/* Traegt Konstante in entprechendes Feld ein. */
+{
+ if(!p) ierror(0);
+/* *p = (union atyps) 0 ; /* rfi: clear unused bits */
+ t&=NU;
+ if(t==CHAR) {p->vchar=vchar;return;}
+ if(t==SHORT) {p->vshort=vshort;return;}
+ if(t==INT) {p->vint=vint;return;}
+ if(t==LONG) {p->vlong=vlong;return;}
+ if(t==LLONG) {p->vllong=vllong;return;}
+ if(t==MAXINT) {p->vmax=vmax;return;}
+ if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+ if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+ if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+ if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+ if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+ if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+ if(t==FLOAT) {p->vfloat=vfloat;return;}
+ if(t==DOUBLE) {p->vdouble=vdouble;return;}
+ if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+ if(t==POINTER) {p->vuint=vuint;return;}
+ if(t==FPOINTER||t==HPOINTER) {p->vulong=vulong;return;}
+}
+
+void eval_const(union atyps *p,int t)
+/* Weist bestimmten globalen Variablen Wert einer CEXPR zu. */
+{
+ int f=t&NQ;
+ if(!p) ierror(0);
+ if(f==MAXINT||(f>=CHAR&&f<=LLONG)){
+ if(!(t&UNSIGNED)){
+ if(f==CHAR) vmax=zc2zm(p->vchar);
+ else if(f==SHORT)vmax=zs2zm(p->vshort);
+ else if(f==INT) vmax=zi2zm(p->vint);
+ else if(f==LONG) vmax=zl2zm(p->vlong);
+ else if(f==LLONG) vmax=zll2zm(p->vllong);
+ else if(f==MAXINT) vmax=p->vmax;
+ else ierror(0);
+ vumax=zm2zum(vmax);
+ vldouble=zm2zld(vmax);
+ }else{
+ if(f==CHAR) vumax=zuc2zum(p->vuchar);
+ else if(f==SHORT)vumax=zus2zum(p->vushort);
+ else if(f==INT) vumax=zui2zum(p->vuint);
+ else if(f==LONG) vumax=zul2zum(p->vulong);
+ else if(f==LLONG) vumax=zull2zum(p->vullong);
+ else if(f==MAXINT) vumax=p->vumax;
+ else ierror(0);
+ vmax=zum2zm(vumax);
+ vldouble=zum2zld(vumax);
+ }
+ }else{
+ if(ISPOINTER(f)){
+ if(f==POINTER)
+ vumax=zui2zum(p->vuint);
+ else
+ vumax=zul2zum(p->vulong);
+ vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+ }else{
+ if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+ else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+ else vldouble=p->vldouble;
+ vmax=zld2zm(vldouble);
+ vumax=zld2zum(vldouble);
+ }
+ }
+ vfloat=zld2zf(vldouble);
+ vdouble=zld2zd(vldouble);
+ vuchar=zum2zuc(vumax);
+ vushort=zum2zus(vumax);
+ vuint=zum2zui(vumax);
+ vulong=zum2zul(vumax);
+ vullong=zum2zull(vumax);
+ vchar=zm2zc(vmax);
+ vshort=zm2zs(vmax);
+ vint=zm2zi(vmax);
+ vlong=zm2zl(vmax);
+ vllong=zm2zll(vmax);
+}
+
+void printval(FILE *f,union atyps *p,int t)
+/* Gibt atyps aus. */
+{
+ t&=NU;
+ if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+ if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+ if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+ if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+ if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+ if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+ if(t==(UNSIGNED|INT)||t==POINTER){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+ if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+ if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+ if(t==MAXINT) printzm(f,p->vmax);
+ if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax);
+}
+
+void emitval(FILE *f,union atyps *p,int t)
+/* Gibt atyps aus. */
+{
+ t&=NU;
+ if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+ if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+ if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+ if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+ if(t==LDOUBLE){emitzld(f,p->vldouble);}
+ if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+ if(t==(UNSIGNED|INT)||t==POINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+ if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+ if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+ if(t==MAXINT) emitzm(f,p->vmax);
+ if(t==(UNSIGNED|MAXINT)) emitzum(f,p->vumax);
+}
+
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+ char *attr;
+ while(p){
+ if(ISPOINTER(p->flags)){
+ p->flags=((p->flags&~NU)|POINTER_TYPE(p->next));
+ if(attr=p->next->attr){
+ if(strstr(attr,STR_NEAR))
+ p->flags=((p->flags&~NU)|POINTER);
+ if(strstr(attr,STR_FAR))
+ p->flags=((p->flags&~NU)|FPOINTER);
+ if(strstr(attr,STR_HUGE))
+ p->flags=((p->flags&~NU)|HPOINTER);
+ }
+ }
+ p=p->next;
+ }
+}
+
+void add_var_hook_post(Var *v)
+{
+ if(use_sec&&(v->storage_class==STATIC||v->storage_class==EXTERN)){
+ char buf[SECLEN+32];
+ sprintf(buf,"section(\"%s\");",use_sec);
+ add_attr(&v->vattr,buf);
+ }
+ if(use_bank>=0&&(v->storage_class==STATIC||v->storage_class==EXTERN)){
+ char buf[64];
+ /*sprintf(buf,"section(\"bank%d\");bank(%d)",use_bank,use_bank);*/
+ sprintf(buf,"bank(%d)",use_bank);
+ add_attr(&v->vattr,buf);
+ }
+}
+
+int decide_reverse(zmax v)
+{
+ if(zmeqto(v,Z1)||zmeqto(v,l2zm(2L)))
+ return 1;
+ if(optspeed)
+ if(zmeqto(v,l2zm(4L))||zmeqto(v,l2zm(8L))||zmeqto(v,l2zm(256L))||zmeqto(v,l2zm(512L)))
+ return 1;
+
+ return 0;
+}
+
+static int is_single_eff_ic(struct IC *p)
+{
+ struct Var *v,*idx;
+ if(p->code!=ADDI2P||(p->typf2&NQ)!=POINTER)
+ return 0;
+ if(!(p->q2.flags&KONST)){
+ if((p->typf&NU)!=(UNSIGNED|CHAR))
+ return 0;
+ if((p->q2.flags&(VAR|DREFOBJ))!=VAR)
+ return 0;
+ if(p->q2.v->storage_class!=AUTO&&p->q2.v->storage_class!=REGISTER)
+ return 0;
+ idx=p->q2.v;
+ }else{
+ idx=0;
+ eval_const(&p->q2.val,p->typf);
+ /* TODO: more precise check considering data type useful? */
+ if(!zmleq(vumax,l2zm(255L)))
+ return 0;
+ return 1;
+ }
+ if(p->q1.flags&DREFOBJ)
+ return 0;
+ if((p->z.flags&(VAR|DREFOBJ))!=VAR)
+ return 0;
+ if(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)
+ return 0;
+ v=p->z.v;
+ for(p=p->next;p;p=p->next){
+ int c=p->code;
+ if(c==LABEL||(c>=BEQ&&c<=BRA))
+ return 1; /* TODO: how elaborate should we test? */
+ if((p->q1.flags&VAR)&&p->q1.v==v){
+ if(p->q1.flags&DREFOBJ)
+ return 1;
+ else
+ return 0;
+ }
+ if((p->q2.flags&VAR)&&p->q2.v==v){
+ if(p->q2.flags&DREFOBJ)
+ return 1;
+ else
+ return 0;
+ }
+ if((p->z.flags&VAR)&&p->z.v==v){
+ if(p->z.flags&DREFOBJ)
+ return 1;
+ else
+ return 0;
+ }
+ if((p->z.flags&VAR)&&p->z.v==idx)
+ return 0;
+ }
+ return 0;
+}
+
+void mark_eff_ics(void)
+{
+ struct IC *p;
+ for(p=first_ic;p;p=p->next){
+ if(is_single_eff_ic(p))
+ p->flags|=EFF_IC;
+ else
+ p->flags&=~EFF_IC;
+ }
+}
diff --git a/machines/6502/machine.dt b/machines/6502/machine.dt
new file mode 100755
index 0000000..eab38c9
--- /dev/null
+++ b/machines/6502/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S16BULE S16BUBE
+
+
diff --git a/machines/6502/machine.h b/machines/6502/machine.h
new file mode 100755
index 0000000..b2c5e45
--- /dev/null
+++ b/machines/6502/machine.h
@@ -0,0 +1,267 @@
+/* 6502 backend for vbcc
+ (c) Volker Barthelmann 2020
+
+*/
+
+/* buil-time configurable options: */
+#define NUM_GPRS 32
+#define NUM_PAIRS (NUM_GPRS/2)
+#define NUM_BIG 4
+#define NUM_BIGP (NUM_BIG/2)
+#define FIXED_SP 1
+
+#include "dt.h"
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef BOOL
+#undef MAXINT
+#undef MAX_TYPE
+
+#define CHAR 1
+#define SHORT 2
+#define INT 3
+#define LONG 4
+#define LLONG 5
+#define FLOAT 6
+#define DOUBLE 7
+#define LDOUBLE 8
+#define VOID 9
+#define POINTER 10
+#define FPOINTER 11
+#define HPOINTER 12
+#define ARRAY 13
+#define STRUCT 14
+#define UNION 15
+#define ENUM 16
+#define FUNKT 17
+#define BOOL 18
+
+#define MAXINT 19
+
+#define MAX_TYPE MAXINT
+
+
+#define POINTER_TYPE(x) pointer_type(x)
+#define POINTER_VARADR(x) pointer_varadr(x)
+extern int pointer_type();
+extern int pointer_varadr();
+#define ISPOINTER(x) ((x&NQ)>=POINTER&&(x&NQ)<=HPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=CHAR&&(x&NQ)<=HPOINTER)
+#define ISINT(x) ((x&NQ)>=CHAR&&(x&NQ)<=LLONG)
+#define PTRDIFF_T(x) ((x)==HPOINTER?LONG:INT)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+ zchar vchar;
+ zuchar vuchar;
+ zshort vshort;
+ zushort vushort;
+ zint vint;
+ zuint vuint;
+ zlong vlong;
+ zulong vulong;
+ zllong vllong;
+ zullong vullong;
+ zmax vmax;
+ zumax vumax;
+ zfloat vfloat;
+ zdouble vdouble;
+ zldouble vldouble;
+};
+
+
+/* internally used by the backend */
+#define FIRST_GPR 8
+#define LAST_GPR (FIRST_GPR+NUM_GPRS-1)
+#define FIRST_PAIR (LAST_GPR+1)
+#define LAST_PAIR (FIRST_PAIR+NUM_PAIRS-1)
+#define FIRST_BIG (LAST_PAIR+1)
+#define LAST_BIG (FIRST_BIG+NUM_BIG-1)
+#define FIRST_BIGP (LAST_BIG+1)
+#define LAST_BIGP (FIRST_BIGP+NUM_BIGP-1)
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Currently possible are (const,gpr) and (gpr,gpr) */
+struct AddressingMode{
+ int flags;
+ int base;
+ int idx;
+ long offset;
+ void *v;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR LAST_BIGP
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 30
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P CHAR
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 0
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 1
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 128
+
+/* Parameters are sometimes passed in registers without __reg. */
+#define HAVE_REGPARMS 1
+
+/* Parameters on the stack should be pushed in order rather than */
+/* in reverse order. */
+#define ORDERED_PUSH FIXED_SP
+
+/* Structure for reg_parm(). */
+struct reg_handle{
+ int regs;
+ int bregs;
+};
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt
+ register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 6 //6
+#define cost_load_reg(x,y) 10 //10
+#define cost_save_reg(x,y) 10 //10
+#define cost_pushpop_reg(x) 2 //12
+
+/* size of buffer for asm-output, this can be used to do
+ peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 8
+
+/* We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+ optimizations on code which can already be implemented by efficient
+ assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we have additional types */
+#define HAVE_EXT_TYPES
+#define HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#define HAVE_INT_SIZET 1
+
+/* we do not need register-pairs */
+#define HAVE_REGPAIRS 1
+
+
+/* do not create CONVERT ICs from integers smaller than int to floats */
+#define MIN_INT_TO_FLOAT_TYPE INT
+
+/* do not create CONVERT ICs from floats to ints smaller than int */
+#define MIN_FLOAT_TO_INT_TYPE INT
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 0
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 0
+
+/* convert multiplications/division by powers of two to shifts */
+#define HAVE_POF2OPT 1
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+/* Use char for return of comparison libcalls */
+#define LIBCALL_CMPTYPE CHAR
+
+/* We prefer BNE rather than BGT. */
+#define HAVE_WANTBNE 1
+
+#define BESTCOPYT CHAR
+
+#define HAVE_AOS4 1
+
+#define CHARCONV(x) cbmconv(x)
+unsigned char cbmconv(unsigned char);
+
+#define ALLOCVLA_REG FIRST_PAIR
+#define ALLOCVLA_INLINEASM "\tlda\tsp\n"\
+ "\tsec\n"\
+ "\tsbc\tr0\n"\
+ "\tsta\tsp\n"\
+ "\tlda\tsp+1\n"\
+ "\tsbc\tr1\n"\
+ "\tsta\tsp+1\n"\
+ "\tlda\tsp\n"\
+ "\tclc\n"\
+ "\tldx\tsp+1\n"\
+ "\tadc\t#___fo\n"\
+ "\tbcc\t*+3\n"\
+ "\tinx\n"
+
+#define FREEVLA_REG FIRST_PAIR
+#define FREEVLA_INLINEASM "\tlda\tr0\n"\
+ "\tsta\tsp\n"\
+ "\tlda\tr1\n"\
+ "\tsta\tsp+1\n"
+
+#define OLDSPVLA_INLINEASM "\tlda\tsp+1\n"\
+ "\ttax\n"\
+ "\tlda\tsp"
+
+#define FPVLA_REG (LAST_PAIR-2)
+
+#define HAVE_TARGET_VARHOOK_POST 1
+
+#define HAVE_DECIDE_REVERSE 1
+
+#define HAVE_TARGET_EFF_IC 1
diff --git a/machines/832/addressingmodes.c b/machines/832/addressingmodes.c
new file mode 100644
index 0000000..6defe37
--- /dev/null
+++ b/machines/832/addressingmodes.c
@@ -0,0 +1,740 @@
+/* search for possible addressing-modes */
+
+/* DONE: Determine whether a given ob is disposable. */
+
+/* ToDo: Look for pairs of ICs with Z set to register,
+ followed by disposable q1 on the same register ->
+ use tmp for that register. (Provided second IC won't trash tmp)
+ Can we avoid the passing register being allocated? */
+
+/* Look for ways to use ldidx when an IC adds to a pointer and the next one dereferences it */
+
+
+#define DEFERREDPOP_FLOWCONTROL 0
+#define DEFERREDPOP_NESTEDCALLS 1
+#define DEFERREDPOP_OK 2
+
+
+#define AM_DEBUG 0
+
+// If the obj doesn't already have an addressing mode, create one and zero it out.
+static void am_alloc(struct obj *o)
+{
+ if (!o->am) {
+ o->am = mymalloc(sizeof(struct AddressingMode));
+ memset(o->am, 0, sizeof(struct AddressingMode));
+ }
+}
+
+
+void am_deferredpop(struct IC *p)
+{
+ struct IC *p2;
+ int pushed=0;
+ int deferredpop=0;
+ int candefer=0;
+ for(;p;p=p->next)
+ {
+ switch(p->code)
+ {
+ case PUSH:
+ pushed+=pushsize(p);
+// printf("Pushing %d bytes, %d so far\n",pushsize(p),pushed);
+ break;
+ case CALL:
+// printf("CALL IC with pushedsize %d\n",pushedargsize(p));
+
+ am_alloc(&p->z);
+
+ /* We detected nested function calls by comparing the amount of data pushed to the
+ stack with this call's pushedargsize(). If they don't match we're dealing with
+ nested calls. If they do match, we might be able to defer stack popping. */
+ if(pushed==pushedargsize(p))
+ {
+// printf("Checking for flow change\n");
+ p2=p->next;
+ candefer=1;
+ while(p2)
+ {
+ switch(p2->code)
+ {
+ /* If we encounter LABEL, COMPARE, TEST or a branch operation then program flow changes
+ before the next PUSH, and we can't defer the stack pop. */
+ case LABEL:
+ case COMPARE:
+ case TEST:
+ case BLT:
+ case BGT:
+ case BLE:
+ case BGE:
+ case BEQ:
+ case BNE:
+ case BRA:
+// printf("Flow control changed - can't defer\n");
+ p->z.am->deferredpop=DEFERREDPOP_FLOWCONTROL;
+ candefer=0;
+ p2=0;
+ break;
+ /* If we encounter another PUSH operation without a flow control change we can defer */
+ case PUSH:
+// printf("Can defer stack popping\n");
+ p2=0;
+ break;
+ default:
+ p2=p2->next;
+ break;
+ }
+ }
+ }
+ else /* pushedargsize() and the contents of the stack differed in size - nested calls. */
+ {
+ p->z.am->deferredpop=DEFERREDPOP_NESTEDCALLS;
+// printf("Nested call - can't defer stack popping\n");
+ candefer=0;
+ }
+
+ if(candefer)
+ {
+ p->z.am->deferredpop=DEFERREDPOP_OK;
+ deferredpop=pushedargsize(p);
+ }
+
+ pushed-=pushedargsize(p);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+static int is_arithmetic_bitwise(int code)
+{
+ switch(code)
+ {
+ case ADD:
+ case ADDI2P:
+ case SUB:
+ case SUBIFP:
+ case MULT:
+ case OR:
+ case XOR:
+ case AND:
+ case LSHIFT:
+ case RSHIFT:
+ return(1);
+ break;
+ }
+ return(0);
+}
+
+
+void am_conversions(struct IC *p)
+{
+ int c;
+ struct IC *p2;
+ struct IC *p3;
+ for (; p; p = p->next) {
+ c = p->code;
+ switch(c)
+ {
+ case BEQ:
+ case BNE:
+ case BLT:
+ case BLE:
+ case BGT:
+ case BGE:
+ case ALLOCREG:
+ case FREEREG:
+ case NOP:
+ break;
+ case CONVERT:
+ printf("(conversion)\n");
+ break;
+
+ default:
+ switch(q1typ(p)&NQ)
+ {
+ case CHAR:
+ case SHORT:
+ printf("IC %d, non-int operation %x, %x\n",c,q1typ(p),ztyp(p));
+ default:
+ break;
+ }
+ break;
+ }
+ }
+}
+
+// Look for 832-specific optimizations
+
+extern zmax sizetab[MAX_TYPE + 1];
+
+void am_simplify(struct IC *p)
+{
+ int c;
+ struct IC *p2;
+ struct IC *p3;
+ struct IC *prev;
+ for (; p; p = p->next) {
+ c = p->code;
+
+ p2=p->next;
+ if(!p2)
+ break;
+ p3=p2->next;
+ if(!p3)
+ break;
+
+ switch(c)
+ {
+ // Check for ADDRESS followed by push - can we merge?
+ case ADDRESS:
+ if((p->z.flags&(REG|DREFOBJ|SCRATCH))!=(REG|SCRATCH))
+ break;
+
+// printf("Address IC candidate: zreg: %d, z flags %x\n",p->z.reg,p->z.flags);
+
+ while(p3)
+ {
+// printf(" next op: %x, q1reg: %d, q1flags: %x, q2reg: %d, q2flags: %x\n",
+// p2->code,p2->q1.reg,p2->q1.flags,p2->q2.reg,p2->q2.flags);
+ switch(p2->code)
+ {
+ case PUSH:
+ if((p2->q1.flags&(REG|DREFOBJ|VARADR))==REG && p2->q1.reg==p->z.reg)
+ {
+// printf("p3 code: %x, reg: %d\n",p3->code,p3->q1.reg);
+ if(p3->code!=FREEREG || p3->q1.reg!=p->z.reg)
+ break;
+// printf("Push: merging\n");
+ p->code=NOP; // Don't prepare the address to a register...
+ p2->q1=p->q1; // Push it directly.
+ p2->q1.flags|=VARADR;
+ p3=0;
+ }
+ break;
+ case FREEREG:
+ if(p2->q1.reg==p->z.reg)
+ {
+// printf("Freereg: bailing out\n");
+ p3=0;
+ }
+ break;
+ default:
+ break;
+ }
+ // Does the IC reference the register?
+ if((p2->q1.flags®) && p2->q1.reg==p->z.reg)
+ p3=0;
+ else if((p2->q2.flags®) && p2->q2.reg==p->z.reg)
+ p3=0;
+ p2=p3;
+ if(p3)
+ p3=p3->next;
+ }
+ break;
+
+ // Check for GETRETURN followed by TEST/COMPARE of call result which is then discarded...
+ case GETRETURN:
+ if((p->z.flags&(REG|DREFOBJ|SCRATCH))!=(REG|SCRATCH))
+ break;
+
+ // FIXME - can do the same for other instructions, provided we don't need to use r0 to derive the second op.
+
+ if(p3->code!=FREEREG || p3->q1.reg!=p->z.reg)
+ break;
+
+ switch(p2->code)
+ {
+ case TEST:
+ if(p2->q1.flags&(REG|DREFOBJ)!=REG || p2->q1.reg!=p->z.reg)
+ break;
+ p->code=NOP; // Don't bother retrieving the return value...
+ p2->q1.reg=p->q1.reg; // Test it directly from return register.
+ break;
+ case SETRETURN:
+ if(p2->q1.flags&(REG|DREFOBJ)!=REG || p2->q1.reg!=p->z.reg)
+ break;
+ p->code=NOP; // Don't bother retrieving the return value...
+ p2->q1.reg=p->q1.reg;
+ break;
+ case COMPARE:
+ if((p2->q1.flags&(REG|DREFOBJ))==REG && p2->q1.reg==p->z.reg)
+ {
+ // Make sure the other op is simple enough not to need r0: FIXME - can we improve this?
+// if((p2->q2.flags&(REG|DREFOBJ))==REG || p2->q2.flags&KONST)
+// {
+ // COMPARE is guaranteed not to touch t1 (r0).
+ p->code=NOP; // Don't bother retrieving the return value...
+ p2->q1.reg=p->q1.reg; // Test it directly from return register.
+// }
+ }
+ else if((p2->q2.flags&(REG|DREFOBJ))==REG && p2->q2.reg==p->z.reg)
+ {
+// if((p2->q1.flags&(REG|DREFOBJ))==REG || p2->q1.flags&KONST)
+// {
+ // COMPARE is guaranteed not to touch t1 (r0).
+ p->code=NOP; // Don't bother retrieving the return value...
+ p2->q2.reg=p->q1.reg; // Test it directly from return register.
+// }
+ }
+ break;
+ }
+ break;
+
+ // Loads cause automatic zero-extension so can avoid conversion
+ // in that case. Arithmetic functions may require conversion - with the exception of AND and (unsigned) SHR,
+ // since neither can result in extra set bits in the MSBs.
+ case CONVERT:
+ if(p2->code==CONVERT)
+ {
+// printf("Found successive Convert ICs\n");
+// printf("p1: %x, %d, %x -> %x, p2: %x, %d, %x -> %x\n",p->z.flags,p->z.reg,q1typ(p),ztyp(p),
+// p2->q1.flags,p2->q1.reg,q1typ(p2),ztyp(p2));
+ if((p->z.flags&(REG|DREFOBJ))==REG && ((p2->q1.flags&(REG|DREFOBJ))==REG) && p->z.reg==p2->q1.reg)
+ {
+// printf("Register match\n");
+ if(((q1typ(p)&NQ)<(ztyp(p)&NQ)) && (q1typ(p)==ztyp(p2)))
+ {
+// printf("Sizes match - nullifying conversion to wider type.\n");
+ p->code=NOP;
+ p2->q1=p->q1;
+ }
+ }
+ } else {
+ if (AM_DEBUG)
+ printf("Checking conversion from %d to %d, %d to %d\n",q1typ(p),ztyp(p),p->q1.reg,p->z.reg);
+ /* Eliminate conversions to wider types within a single register if the value is unsigned */
+ if((p->z.flags&(REG|DREFOBJ))==REG && ((p->q1.flags&(REG|DREFOBJ))==REG) && p->z.reg==p->q1.reg) {
+ if((q1typ(p)&UNSIGNED) && (sizetab[q1typ(p) & NQ] < sizetab[ztyp(p) & NQ])) {
+ if (AM_DEBUG)
+ printf("Eliminating unnecessary conversion\n");
+ p->code=NOP;
+ }
+ }
+ }
+// printic(stdout,p);
+ break;
+
+ // Look for situations where an arithmetic operation will have set flags,
+ // rendering an explicit TEST unnecessary.
+ case TEST:
+ prev=p->prev;
+ if(prev)
+ {
+// printf("TEST found, evaluating previous IC\n");
+ if(is_arithmetic_bitwise(prev->code))
+ {
+// printf("Arithmetic / bitwise IC found\n");
+// printf("%x, %d, %x, %d\n",prev->z.flags,prev->z.reg,p->q1.flags,p->q1.reg);
+ if((prev->z.flags&(REG|DREFOBJ))==REG && ((p->q1.flags&(REG|DREFOBJ))==REG) && prev->z.reg==p->q1.reg)
+ {
+// printf("Register match\n");
+ p->code=NOP;
+ }
+ }
+ }
+ break;
+
+ default:
+ // Look for cases where multiple arithmetic / bitwise instructions are chained and could
+ // avoid writing to an intermediate register...
+ if(is_arithmetic_bitwise(c) && is_arithmetic_bitwise(p2->code) && p3->code==FREEREG)
+ {
+ if (AM_DEBUG)
+ printf("Evaluating pair of arithmetic ops followed by freereg...\n");
+ if(((p->z.flags&(REG|DREFOBJ))==REG) && ((p2->q1.flags&(REG|DREFOBJ))==REG) && ((p2->z.flags&(REG|DREFOBJ))==REG))
+ {
+ if (AM_DEBUG)
+ printf("Ops are all register based...\n");
+ if (AM_DEBUG)
+ printf("p1.q1: %s, p1.q2: %s, p1.z: %s - p2.q1: %s, p2.q2: %s, p2.z: %s\n",
+ regnames[p->q1.reg],regnames[p->q2.reg],regnames[p->z.reg],
+ regnames[p2->q1.reg],regnames[p2->q2.reg],regnames[p2->z.reg]);
+ if(p2->q1.reg==p3->q1.reg && p->z.reg==p2->q1.reg && p2->q1.reg!=p2->z.reg && p2->q2.reg!=p2->z.reg)
+ {
+ if (AM_DEBUG)
+ printf("Freereg matches - adjusting\n");
+ p->z.reg=p2->z.reg;
+ p2->q1.reg=p2->z.reg;
+ }
+ }
+ // FIXME - explore the lifetime of the register we've just avoided; can we
+ // avoid allocating / freeing it? Won't help the code-generator but might be
+ // able to avoid saving / restoring it in the function head / tail.
+ }
+ else
+ {
+ // Look specificially for addt candidates...
+ if(c==ADD || c==ADDI2P)
+ {
+ int zr=(p->z.flags&(REG|DREFOBJ))==REG ? 1 : 0;
+
+// printf("add %x, %x, %x, %s, %s, %s\n",p->q1.flags,p->q2.flags,p->z.flags,
+// regnames[p->q1.reg],regnames[p->q2.reg],regnames[p->z.reg]);
+ if((p->q1.flags&(REG|DREFOBJ))==REG)
+ {
+ if(!zr || p->z.reg!=p->q1.reg)
+ {
+ if((p->q2.flags&(REG|DREFOBJ))==REG) // reg + reg => reg
+ {
+ // All three operands are registers - are they all different?
+ if((zr || p->z.reg!=p->q2.reg) && p->q1.reg!=p->q2.reg)
+ {
+ am_alloc(&p->q1);
+ p->q1.am->type=AM_ADDT;
+ if (AM_DEBUG)
+ printf("Marked addt candidate\n");
+ }
+ }
+ if((p->q2.flags&(KONST|DREFOBJ))==KONST) // reg + const => reg
+ {
+ am_alloc(&p->q1);
+ p->q1.am->type=AM_ADDT;
+ if (AM_DEBUG)
+ {
+ printf("Marked addt candidate\n");
+ printf("Reg + Konst => Reg\n");
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+}
+
+void am_disposable(struct IC *p, struct obj *o)
+{
+ struct IC *p2;
+ int disposable = 0;
+ if (o->flags & REG) {
+ // Cover the case where q1 or q2 are the same register as z.
+ if(o!=&p->z)
+ {
+ // We're writing to the same register as we're reading from - not disposable!
+ if((p->z.flags®) && p->z.reg==o->reg)
+ return;
+ }
+ p2 = p->next;
+ while (p2) {
+ if (p2->code == FREEREG && p2->q1.reg == o->reg) {
+ if (AM_DEBUG)
+ printf("\t(%s disposable.)\n", regnames[o->reg]);
+ am_alloc(o);
+ o->am->disposable = 1;
+ return;
+ }
+ if (((p2->q1.flags & REG)
+ && p2->q1.reg == o->reg)
+ || ((p2->q2.flags & REG)
+ && p2->q2.reg == o->reg)
+ || ((p2->z.flags & REG)
+ && p2->z.reg == o->reg)) {
+ //Found another instruction referencing reg - not disposable.
+ return;
+ }
+ switch (p2->code) {
+ case CALL:
+ case BEQ:
+ case BNE:
+ case BLT:
+ case BGE:
+ case BLE:
+ case BGT:
+ case BRA:
+ // Control flow changed, erring on the side of safety - not disposable.
+ return;
+ break;
+ default:
+ break;
+ }
+ p2 = p2->next;
+ }
+ }
+}
+
+struct obj *throwaway_reg(struct IC *p,int reg)
+{
+ struct obj *result=0;
+ if (AM_DEBUG)
+ printf("\tChecking IC for reg %s\n", regnames[reg]);
+ if(p) {
+ if((p->q1.flags®) && p->q1.reg==reg) {
+ am_disposable(p,&p->q1);
+ if(p->q1.am && p->q1.am->disposable)
+ result=&p->q1;
+ } else if((p->z.flags®) && p->z.reg==reg) {
+ am_disposable(p,&p->z);
+ if(p->z.am && p->z.am->disposable)
+ result=&p->z;
+ }
+ }
+ if (AM_DEBUG)
+ printf("\tReturning %x\n", result);
+ return(result);
+}
+
+
+struct IC *am_find_adjustment(struct IC *p, int reg)
+{
+ struct IC *p2 = p->next;
+ // FIXME - limit how many steps we check...
+ /* Look for a post-increment */
+ while (p2) {
+// printf("\t\tChecking code %d\n",p2->code);
+ if (p2->code == ADDI2P) {
+// if (AM_DEBUG)
+// printf("\tFound Addi2p to register %s \n", regnames[p2->z.reg]);
+ if ((p2->q2.flags & KONST) && (p2->z.flags & REG)) {
+ if (p2->z.reg == reg) {
+ if (AM_DEBUG)
+ printf("\t\tAdjusting the correct register - match found\n");
+ break;
+ } else {
+ if(p2 && p2->q1.reg == reg) {
+ if (AM_DEBUG)
+ printf("\t\tWriting to different reg - is source reg disposable? ");
+ am_disposable(p2, &p2->q1);
+ if(p2->q1.am && p2->q1.am->disposable){
+ if (AM_DEBUG)
+ printf("yes\n");
+ break;
+ } else {
+ if (AM_DEBUG)
+ printf("no - bailing out\n");
+ p2=0;
+ }
+ } else {
+ if (AM_DEBUG)
+ printf("\t\tWrong register - keep looking\n");
+ }
+ }
+ } else {
+ if (AM_DEBUG)
+ printf("\t\tnot a constant, however - bailing out.\n");
+ p2 = 0;
+ }
+ } else if (((p2->q1.flags & (REG | DREFOBJ)) && p2->q1.reg == reg)
+ || ((p2->q2.flags & (REG | DREFOBJ))
+ && p2->q2.reg == reg)
+ || ((p2->z.flags & (REG | DREFOBJ))
+ && p2->z.reg == reg)) {
+ if (AM_DEBUG)
+ printf("\t\tFound another instruction referencing reg - bailing out\n");
+ p2 = 0;
+ } else if (p2->code>=BEQ && p2->code<=BRA) {
+ if (AM_DEBUG)
+ printf("\t\tFound a branch instruction - bailing out\n");
+ p2 = 0;
+ } else if (p2->code>=LABEL) {
+ if (AM_DEBUG)
+ printf("\t\tFound a label - bailing out\n");
+ p2 = 0;
+ }
+ if (p2)
+ p2 = p2->next;
+ }
+ if (p2)
+ return (p2);
+ if (AM_DEBUG)
+ printf("\tNo postincrements found - checking for predecrements\n");
+ /* Search for a predecrement */
+ p2 = p->prev;
+ while (p2) {
+ if (p2->code == SUBIFP) {
+ if (AM_DEBUG)
+ printf("\t\tFound subifp to register %s \n", regnames[p2->z.reg]);
+ if ((p2->q2.flags & KONST) && (p2->z.flags & REG)) {
+ if (p2 && p2->z.reg == reg) {
+ if (AM_DEBUG)
+ printf("\t\tAdjusting the correct register - match found\n");
+ break;
+ } else {
+ if(p2 && p2->q1.reg == reg) {
+ if (AM_DEBUG)
+ printf("\t\tWriting to different reg - is source reg disposable? ");
+ am_disposable(p2, &p2->q1);
+ if(p2->q1.am && p2->q1.am->disposable){
+ if (AM_DEBUG)
+ printf("yes\n");
+ break;
+ } else {
+ if (AM_DEBUG)
+ printf("no - bailing out\n");
+ }
+ }
+ }
+ } else {
+ if (AM_DEBUG)
+ printf("\t\tnot a constant, however - bailing out.\n");
+ p2 = 0;
+ }
+ } else if (((p2->q1.flags & (REG | DREFOBJ)) && p2->q1.reg == reg)
+ || ((p2->q2.flags & (REG | DREFOBJ))
+ && p2->q2.reg == reg)
+ || ((p2->z.flags & (REG | DREFOBJ))
+ && p2->z.reg == reg)) {
+ if (AM_DEBUG)
+ printf("\t\tFound another instruction referencing reg - bailing out\n");
+ p2 = 0;
+ }
+ // FIXME - check for control flow changes
+ if (p2)
+ p2 = p2->prev;
+ }
+ return (p2);
+}
+
+// If we have a candidate for pre/post increment/decrement, validate that we can use it,
+// and return the offset. Zero if we can't use it.
+int am_get_adjvalue(struct IC *p, int type, int target)
+{
+ int offset = p->q2.val.vmax;
+ if (p->code == SUBIFP)
+ offset = -offset;
+ if (AM_DEBUG)
+ printf("Offset is %d, type is %d, writing to target? %s\n", offset, type & NQ, target ? "yes" : "no");
+ // Validate offset against type and CPU's capabilities.
+ switch (type & NQ) {
+ case CHAR: // We only support postincrement for CHARs
+ if (offset != 1)
+ offset = 0;
+ if (p->code == SUBIFP)
+ offset = 0;
+ break;
+ case INT:
+ case LONG:
+ case POINTER: // We support post-increment and predecrement for INTs/LONGs/PTRs
+// if(target && offset!=-4) // We only support predec for writing.
+ if (target && ((offset != -4) && (offset != 4))) // We now support predec and postinc for writing.
+ offset = 0;
+ if (!target && offset != 4) // We only support postinc for reading
+ offset = 0;
+ if (p->code == ADDI2P && offset != 4)
+ offset = 0;
+ if (p->code == SUBIFP && offset != -4)
+ offset = 0;
+ break;
+ case SHORT: // We don't support either mode for shorts or anything else.
+ default:
+ offset = 0;
+ }
+ if (AM_DEBUG)
+ printf("Validated offset is %d\n", offset);
+ return (offset);
+}
+
+void am_prepost_incdec(struct IC *p, struct obj *o)
+{
+ struct IC *p2 = 0;
+ int type;
+
+ if (o->flags & (REG) && (o->flags & DREFOBJ)) {
+ if (AM_DEBUG)
+ printf("Dereferencing register %s - searching for adjustments\n", regnames[o->reg]);
+ p2 = am_find_adjustment(p, o->reg);
+
+ if (p2) // Did we find a candidate for postinc / predec?
+ {
+ int adj;
+ switch (p->code) {
+ case CONVERT:
+ // Are we considering q1 or z?
+ if(o==&p->z)
+ type = p->typf;
+ else
+ type = p->typf2;
+ if (AM_DEBUG)
+ printf("\tConvert operation - type is %d\n", type);
+ break;
+ default:
+ if (AM_DEBUG)
+ printf("\tRegular operation - type is %d\n", p->typf);
+ type = p->typf;
+ break;
+ }
+ adj = am_get_adjvalue(p2, type, o == &p->z); // Validate the adjustment
+ if (adj) {
+ obj *tempob;
+ switch(p2->code)
+ {
+ case ADDI2P:
+ case SUBIFP:
+ // Are the source and destination regs the same?
+ if(p2->q1.reg==p2->z.reg) {
+ p2->code=NOP; // Nullify the manual adjustment if we can do it as an opcode side-effect
+ break;
+ }
+
+ // Check next IC to see if it's disposable, and referencing the same register:
+ if(tempob=throwaway_reg(p2->next,p2->z.reg)) {
+ if (AM_DEBUG)
+ printf("\tChangingnext IC from reg %s to reg %s\n", regnames[tempob->reg], regnames[p2->q1.reg]);
+ tempob->reg=p2->q1.reg; // Adjust the register referenced in the next IC.
+ p2->code=NOP; // Nullify the adjustment since we've aliased the register
+ }
+ else
+ p2->code=ASSIGN; // Otherwise replace it with an assign if the registers aren't equal.
+ break;
+ default:
+ p2->code = NOP; // Nullify the manual adjustment if we can do it as an opcode side-effect
+ break;
+ }
+ am_alloc(o);
+ o->am->type = (adj > 0) ? AM_POSTINC : AM_PREDEC;
+ }
+ }
+ }
+}
+
+#define getreg(x) (x.flags® ? x.reg : 0)
+
+static void find_addressingmodes(struct IC *p)
+{
+ int c;
+ struct obj *o;
+ struct AddressingMode *am;
+
+ am_deferredpop(p);
+ am_simplify(p);
+// am_conversions(p);
+
+ for (; p; p = p->next) {
+ c = p->code;
+
+ // Have to make sure that operands are different registers!
+ if ((getreg(p->q1) == getreg(p->q2))
+ || (getreg(p->q1) == getreg(p->z))) {
+ if (getreg(p->q1))
+ if (AM_DEBUG)
+ printf("Collision between q1 and q2 or z - ignoring\n");
+ } else
+ am_prepost_incdec(p, &p->q1);
+
+ if ((getreg(p->q1) == getreg(p->q2))
+ || (getreg(p->q2) == getreg(p->z))) {
+ if (getreg(p->q1))
+ if (AM_DEBUG)
+ printf("Collision between q2 and q1 or z - ignoring\n");
+ } else
+ am_prepost_incdec(p, &p->q2);
+
+ if ((getreg(p->q1) == getreg(p->z))
+ || (getreg(p->q2) == getreg(p->z))) {
+ if (getreg(p->z))
+ if (AM_DEBUG)
+ printf("Collision between z and q1 or q2 - ignoring\n");
+ } else
+ am_prepost_incdec(p, &p->z);
+// printic(stdout,p);
+
+ am_disposable(p, &p->q1);
+ am_disposable(p, &p->q2);
+ am_disposable(p, &p->z);
+ }
+}
+
diff --git a/machines/832/inlinememcpy.c b/machines/832/inlinememcpy.c
new file mode 100644
index 0000000..aa146f5
--- /dev/null
+++ b/machines/832/inlinememcpy.c
@@ -0,0 +1,262 @@
+/* FIXME - emit a memcpy function with weak linkage if -size is specified */
+
+void emit_inlinememcpy(FILE *f,struct IC *p, int t)
+{
+ int srctype=t;
+ int srcr = t1;
+ int dstr=0;
+ int cntr=0;
+ int savec=1;
+ int saved=0;
+ int wordcopy;
+ int bytecopy;
+ zmax copysize = opsize(p);
+ int unrollwords=0;
+ int unrollbytes=0;
+
+ // Can we create larger code in the interests of speed? If so, partially unroll the copy.
+ wordcopy = copysize & ~3;
+ bytecopy = copysize - wordcopy;
+
+ if (wordcopy < 32 && !optsize)
+ unrollwords=1;
+ if (bytecopy < 5)
+ unrollbytes=1;
+
+ cleartempobj(f,t1);
+ cleartempobj(f,tmp);
+
+ // Even if a register is available we still have to save it because the current function wouldn't
+ // but the parent function may be using it. Therefore we might as well use a hardcoded register.
+ dstr=t1+1;
+ if(p->z.flags&(REG|DREFOBJ)==REG)
+ dstr=p->z.reg;
+ // FIXME - check this logic. If the target is a register, it may not be a scratch register.
+ if(regs[dstr]) // Scratch register - only need to save if it's in use?
+ {
+ saved=1;
+ emit(f,"\tmt\t%s\n",regnames[dstr]);
+ emit(f,"\tstdec\t%s\n",regnames[sp]);
+ pushed+=4;
+ }
+
+ cntr=t1+2;
+ if(cntr==dstr) /* Use r1 instead of r2 if the dest pointer is in r2 already. */
+ cntr=t1+1;
+ if(cntr==srcr) /* If cntr && srcr now clash, use r3 instead */
+ cntr=t1+3;
+
+ if((unrollwords && unrollbytes) || regs[cntr]==0)
+ savec=0;
+ else {
+ emit(f,"\tmt\t%s\n",regnames[cntr]);
+ emit(f,"\tstdec\t%s\n",regnames[sp]);
+ pushed+=4;
+ }
+
+ /* Prepare source register */
+ if ((t & NQ) == CHAR && (opsize(p) != 1)) {
+ emit(f, "\t\t\t\t\t// (char with size!=1 -> array of unknown type)\n");
+ srctype = ARRAY; // FIXME - ugly hack
+ }
+ emit_objtoreg(f, &p->q1, srctype,srcr);
+
+ /* Prepare destination register */
+
+ emit_prepobj(f, &p->z, t, dstr, 0);
+
+ if (p->z.flags & REG) {
+ if(p->z.reg!=dstr) {// Move target register to dstr
+ emit(f, "\tmt\t%s\n", regnames[p->z.reg]);
+ emit(f, "\tmr\t%s\n", regnames[dstr]);
+ }
+ }
+
+ emit(f, "\t\t\t\t\t// Copying %d words and %d bytes to %s\n", wordcopy / 4, bytecopy,
+ p->z.v ? p->z.v->identifier : "(null)");
+// printf("memcpy: Copying %d words and %d bytes to %s\n", wordcopy / 4, bytecopy,
+// p->z.v ? p->z.v->identifier : "(null)");
+
+// if(!p->z.v)
+// printf("No z->v: z flags: %x\n",p->z.flags);
+
+ // Prepare the copy
+ // FIXME - we don't necessarily have a valid z->v! If not, where does the target come from?
+ // Stack based variable?
+
+ if (unrollwords) {
+ wordcopy >>= 2;
+ if (wordcopy) {
+ emit(f, "\t\t\t\t\t// Copying %d words to %s\n", wordcopy, p->z.v ? p->z.v->identifier : "(null)");
+ }
+ while (wordcopy--) {
+ emit(f, "\tldinc\t%s\n\tstinc\t%s\n", regnames[srcr], regnames[dstr]);
+ }
+ } else if(wordcopy) {
+ emit(f, "\t\t\t\t\t// Copying %d words to %s\n", wordcopy / 4, p->z.v ? p->z.v->identifier : "(null)");
+ // Copy bytes...
+ emit_constanttotemp(f, wordcopy);
+ emit(f, "\taddt\t%s\n", regnames[dstr]);
+ emit(f, "\tmr\t%s\n", regnames[cntr]);
+ emit(f, ".cpy%swordloop%d:\n", p->z.v ? p->z.v->identifier : "null", loopid);
+ emit(f, "\tldinc\t%s\n\tstinc\t%s\n", regnames[srcr], regnames[dstr]);
+ emit(f, "\tmt\t%s\n\tcmp\t%s\n", regnames[dstr], regnames[cntr]);
+ emit(f, "\tcond\tNEQ\n");
+ emit(f, "\t\t.lipcrel\t.cpy%swordloop%d\n", p->z.v ? p->z.v->identifier : "null", loopid);
+ emit(f, "\t\tadd\t%s\n", regnames[pc]);
+ }
+
+ if (unrollbytes) {
+ if (bytecopy)
+ emit(f, "\t\t\t\t\t// Copying %d byte tail to %s\n", bytecopy,p->z.v ? p->z.v->identifier : "null");
+ while (bytecopy--)
+ emit(f, "\tldbinc\t%s\n\tstbinc\t%s\n", regnames[srcr], regnames[dstr]);
+ } else if (bytecopy) {
+ emit(f, "\t\t\t\t\t// Copying %d bytes to %s\n", bytecopy, p->z.v ? p->z.v->identifier : "null");
+ // Copy bytes...
+ emit_constanttotemp(f, bytecopy);
+ emit(f, "\taddt\t%s\n", regnames[dstr]);
+ emit(f, "\tmr\t%s\n", regnames[cntr]);
+ emit(f, ".cpy%sloop%d:\n", p->z.v ? p->z.v->identifier : "null", loopid);
+ emit(f, "\tldbinc\t%s\n\tstbinc\t%s\n", regnames[srcr], regnames[dstr]);
+ emit(f, "\tmt\t%s\n\tcmp\t%s\n", regnames[dstr], regnames[cntr]);
+ emit(f, "\tcond\tNEQ\n");
+ emit(f, "\t\t.lipcrel\t.cpy%sloop%d\n", p->z.v ? p->z.v->identifier : "null", loopid);
+ emit(f, "\t\tadd\t%s\n", regnames[pc]);
+
+ }
+ // cleanup
+ if(savec) {
+ emit(f,"\tldinc\t%s\n",regnames[sp]);
+ emit(f,"\tmr\t%s\n",regnames[cntr]);
+ pushed-=4;
+ }
+ if(saved) {
+ emit(f,"\tldinc\t%s\n",regnames[sp]);
+ emit(f,"\tmr\t%s\n",regnames[dstr]);
+ pushed-=4;
+ }
+ cleartempobj(f,t1);
+ cleartempobj(f,tmp);
+ loopid++;
+}
+
+
+/* Similar to inlinememcpy, but copies an array or struct to the stack */
+
+void emit_inlinepush(FILE *f,struct IC *p, int t)
+{
+ int srcr = t1;
+ int dstr=0;
+ int cntr=0;
+ int savec=1;
+ int saved=0;
+ int wordcopy;
+ int bytecopy;
+ zmax copysize = opsize(p);
+ int unrollwords=0;
+ int unrollbytes=0;
+
+ // Can we create larger code in the interests of speed? If so, partially unroll the copy.
+ wordcopy = copysize & ~3;
+ bytecopy = copysize - wordcopy;
+
+ if ((wordcopy < 32 && !optsize) || (wordcopy<16))
+ unrollwords=1;
+ if (bytecopy < 5)
+ unrollbytes=1;
+
+ cleartempobj(f,t1);
+ cleartempobj(f,tmp);
+
+ // Even if a register is available we still have to save it because the current function wouldn't
+ // but the parent function may be using it. Therefore we might as well use a hardcoded register.
+ dstr=sp;
+
+ // FIXME - don't necessarily need the counter register if the copy is small...
+
+ /* Is our source a register? If so, set srcr accordingly */
+ if (p->q1.flags & REG) {
+ srcr=p->q1.reg;
+ cntr=t1;
+ } else
+ cntr=t1+2;
+
+ if((unrollwords && unrollbytes) || regs[cntr]==0)
+ savec=0;
+ else {
+ emit(f,"\tmt\t%s\n",regnames[cntr]);
+ emit(f,"\tstdec\t%s\n",regnames[sp]);
+ pushed+=4;
+ }
+
+ emit(f, "\t\t\t\t\t// Copying %d words and %d bytes to stack\n", wordcopy / 4, bytecopy);
+
+// if(!p->z.v)
+// printf("No z->v: z flags: %x\n",p->z.flags);
+
+ // Prepare the copy
+ emit_prepobj(f, &p->q1, t,srcr,0);
+
+ // Make room on the stack for the copied object
+
+ emit(f,"\t.liconst\t%d\n",pushsize(p));
+ emit(f,"\tsub\t%s\n",regnames[sp]);
+
+ if (unrollwords) {
+ wordcopy >>= 2;
+ if (wordcopy) {
+ emit(f, "\t\t\t\t\t// Copying %d words to stack\n", wordcopy);
+ }
+ while (wordcopy--) {
+ emit(f, "\tldinc\t%s\n\tstinc\t%s\n", regnames[srcr], regnames[dstr]);
+ }
+ } else {
+ emit(f, "\t\t\t\t\t// Copying %d words to stack\n", wordcopy / 4);
+ // Copy bytes...
+ emit_constanttotemp(f, wordcopy);
+ emit(f, "\taddt\t%s\n", regnames[dstr]);
+ emit(f, "\tmr\t%s\n", regnames[cntr]);
+ emit(f, ".cpystackwordloop%d:\n", loopid);
+ emit(f, "\tldinc\t%s\n\tstinc\t%s\n", regnames[srcr], regnames[dstr]);
+ emit(f, "\tmt\t%s\n\tcmp\t%s\n", regnames[dstr], regnames[cntr]);
+ emit(f, "\tcond\tNEQ\n");
+ emit(f, "\t\t.lipcrel\t.cpystackwordloop%d\n", loopid);
+ emit(f, "\t\tadd\t%s\n", regnames[pc]);
+ }
+
+ if (unrollbytes) {
+ if (bytecopy)
+ emit(f, "\t\t\t\t\t// Copying %d byte tail to stack\n", bytecopy);
+ while (bytecopy--)
+ emit(f, "\tldbinc\t%s\n\tstbinc\t%s\n", regnames[srcr], regnames[dstr]);
+ } else {
+ emit(f, "\t\t\t\t\t// Copying %d bytes to stack\n", bytecopy);
+ // Copy bytes...
+ emit_constanttotemp(f, bytecopy);
+ emit(f, "\taddt\t%s\n", regnames[dstr]);
+ emit(f, "\tmr\t%s\n", regnames[cntr]);
+ emit(f, ".cpystackloop%d:\n", loopid);
+ emit(f, "\tldbinc\t%s\n\tstbinc\t%s\n", regnames[srcr], regnames[dstr]);
+ emit(f, "\tmt\t%s\n\tcmp\t%s\n", regnames[dstr], regnames[cntr]);
+ emit(f, "\tcond\tNEQ\n");
+ emit(f, "\t\t.lipcrel\t.cpystackloop%d\n", loopid);
+ emit(f, "\t\tadd\t%s\n", regnames[pc]);
+
+ }
+ // cleanup
+
+ // Reset the stack pointer since we've been blithely post-incrementing it.
+ emit(f,"\t.liconst\t%d\n",opsize(p));
+ emit(f,"\tsub\t%s\n",regnames[sp]);
+
+ if(savec) {
+ emit(f,"\tldinc\t%s\n",regnames[sp]);
+ emit(f,"\tmr\t%s\n",regnames[cntr]);
+ pushed-=4;
+ }
+ cleartempobj(f,t1);
+ cleartempobj(f,tmp);
+ loopid++;
+}
+
diff --git a/machines/832/libcalls.c b/machines/832/libcalls.c
new file mode 100644
index 0000000..291f062
--- /dev/null
+++ b/machines/832/libcalls.c
@@ -0,0 +1,50 @@
+/* First steps towards LONG LONG and FLOAT support.
+ 832 is not well suited to handling these types. */
+
+char *use_libcall(int code,int typf1, int typf2)
+{
+ char *result=0;
+// printf("Querying libcall for %d, %d, %d\n",code,typf1,typf2);
+ switch(code)
+ {
+ case CONVERT:
+ if((typf1&NU)==LLONG && (typf2&NU)==INT)
+ return("__conv_ll_int\n");
+ if((typf1&NU)==(UNSIGNED|LLONG) && (typf2&NU)==(UNSIGNED|INT))
+ return("__conv_ull_uint\n");
+ if((typf1&NU)==INT && (typf2&NU)==LLONG)
+ return("__conv_int_ll\n");
+ if((typf1&NU)==(UNSIGNED|INT) && (typf2&NU)==(UNSIGNED|LLONG))
+ return("__conv_uint_ull\n");
+ case ADD:
+ if((typf1&NU)==LLONG)
+ return("__add_ll_ll\n");
+ if((typf1&NU)==(UNSIGNED|LLONG))
+ return("__add_ull_ull\n");
+ case MULT:
+ if((typf1&NU)==LLONG && (typf2&NU)==INT)
+ return("__mul_ll_int\n");
+ if((typf1&NU)==(UNSIGNED|LLONG) && (typf2&NU)==(UNSIGNED|INT))
+ return("__mul_ull_uint\n");
+ if((typf1&NU)==LLONG && (typf2&NU)==LLONG)
+ return("__mul_ll_ll\n");
+ if((typf1&NU)==(UNSIGNED|LLONG) && (typf2&NU)==(UNSIGNED|LLONG))
+ return("__mul_ull_ull\n");
+ default:
+ break;
+ }
+ return(result);
+}
+
+void declare_builtins()
+{
+ declare_builtin("__conv_int_ll",INT,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__conv_ull_ull",UNSIGNED|INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__add_ll_ll",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__add_ull_ull",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__mul_ll_ll",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__mul_ull_ull",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__mul_ll_int",LLONG,LLONG,0,INT,0,1,0);
+ declare_builtin("__mul_ull_uint",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|INT,0,1,0);
+}
+
diff --git a/machines/832/machine.c b/machines/832/machine.c
new file mode 100644
index 0000000..03899e3
--- /dev/null
+++ b/machines/832/machine.c
@@ -0,0 +1,2420 @@
+/* EightThirtyTwo backend for vbcc,
+ based on the generic RISC backend
+
+ The CPU targeted by this backend, and the latest version, can be found at
+ https://github.com/robinsonb5/EightThirtyTwo
+
+*/
+
+// DONE - T2 no longer used at all - frees up a register for the main code generator
+
+// DONE Update the memcpy code to save/allocate registers if needed.
+// DONE Update the div code likewise.
+
+// Complete the work on object tracking. In particular take care of tracking an object vs
+// its address.
+// Also track via addressing-mode analysis whether or not it's valuable to save a value;
+// Values can also be saved to otherwise unused registers. (The compiler is almost certainly
+// already smart enough to make use of unused registers for this, however!)
+
+// DONE: eliminate unnecessary register shuffling for compare.
+
+// DONE: Implement block copying
+
+// DONE: Implement division / modulo using library code.
+// DONE: Mark registers as disposable if their contents are never used beyond the current op.
+
+// Look at ways of improving code efficiency. Look for situations where the output of one IC
+// becomes the input of another? Would make a big difference when registers are all in use.
+
+// Minus could be optimised for the in-register case.
+
+// DONE: Do we need to reserve two temp registers? Turns out one was sufficient, and giving
+// the code generator an extra one to play with helped a great deal.
+
+// Restrict byte and halfword storage to static and extern types, not stack-based variables.
+// (Having learned more, bytes and halfwords on the stack are fine, the complication is with
+// function parameters, which are promoted to int - thus the size modifier will be different
+// for parameters and local variables even though both live on the stack.)
+
+// DONE - Avoid moving registers for cmp and test when possible.
+
+// Condition code for test may well be already set by previous load.
+// Done for TEST, do the same for comparisons?
+
+// Deal with dereferencing in temp caching - can we avoid repeated setups in tmp, maybe using r0?
+
+
+#include "supp.h"
+
+#define DBGMSG 1
+
+static char FILE_[] = __FILE__;
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[] =
+ "vbcc EightThirtyTwo code-generator, (c) 2019/2020 by Alastair M. Robinson\nBased on the generic RISC example backend (c) 2001 by Volker Barthelmann";
+
+/* Commandline-flags the code-generator accepts:
+ 0: just a flag
+ VALFLAG: a value must be specified
+ STRINGFLAG: a string can be specified
+ FUNCFLAG: a function will be called
+ apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF] = { 0 };
+
+#define FLAG_PIC 0
+#define FLAG_LE 1
+#define FLAG_BE 2
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+ they collide with the frontend */
+/* 832-specific flags, "fpic" enables position independent code - name chosen to match gcc */
+char *g_flags_name[MAXGF] = { "fpic","el","eb" };
+
+char flag_832_bigendian;
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF] = { 0,0,0 };
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE + 1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE + 1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE + 1];
+zumax t_max[MAX_TYPE + 1];
+zumax tu_max[MAX_TYPE + 1];
+
+/* Names of all registers. will be initialized in init_cg(),
+ register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR + 1];
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR + 1];
+
+/* a type which can store each register. */
+struct Typ *regtype[MAXR + 1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR + 1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR + 1];
+
+/* specifies the priority for the register-allocator, if the same
+ estimated cost-saving can be obtained by several registers, the
+ one with the highest priority will be used */
+int reg_prio[MAXR + 1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle = { 0, 0 };
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[] = { "__interrupt", "__ctor", "__dtor", "__weak", 0 };
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+#define USE_COMMONS 0
+
+/* alignment of basic data-types, used to initialize align[] */
+/* In actual fact 832 has full load/store alignment so this is negotiable based on -speed / -size flags. */
+static long malign[MAX_TYPE + 1] = { 1, 1, 2, 4, 4, 4, 4, 8, 8, 1, 4, 1, 1, 1, 4, 1 };
+
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE + 1] = { 1, 1, 2, 4, 4, 8, 4, 8, 8, 0, 4, 0, 0, 0, 4, 0 };
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp = { LONG }, ldbl = {
+DOUBLE}, lchar = {
+CHAR};
+
+/* macros defined by the backend */
+static char *marray[] = { "__section(x)=__vattr(\"section(\"#x\")\")",
+ "__EIGHTTHIRTYTWO__",
+ "__constructor(pri)=__vattr(\"ctor(\"#pri\")\")",
+ "__destructor(pri)=__vattr(\"dtor(\"#pri\")\")",
+ "__weak=__vattr(\"weak\")",
+ 0
+};
+
+/* special registers */
+static int pc; /* Program counter */
+static int sp; /* Stackpointer */
+static int tmp;
+static int t1, t2; /* temporary gprs */
+static int f1, f2, f3; /* temporary fprs */
+static int loopid = 0; /* must be unique for every function in a compilation unit */
+
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+//static long stack;
+static int section = -1, newobj;
+static char *codename = "\t.section\t.text";
+static char *dataname = "\t.section\t.data";
+static char *bssname = "\t.section\t.bss";
+static char *rodataname = "\t.section\t.rodata";
+static int sectionid=0;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix = "l", *idprefix = "_";
+
+/* variables to keep track of the current stack-offset in the case of
+ a moving stack-pointer */
+static long pushed;
+static long notyetpopped;
+
+static long localsize, rsavesize, argsize;
+
+static int count_constantchunks(zmax v);
+static void emit_constanttotemp(FILE * f, zmax v);
+static void emit_statictotemp(FILE * f, char *lab, int suffix, int offset);
+static void emit_externtotemp(FILE * f, char *lab, int offset);
+static void emit_pcreltotemp2(FILE *f,struct obj *p);
+
+static void emit_prepobj(FILE * f, struct obj *p, int t, int reg, int offset);
+static int emit_objtoreg(FILE * f, struct obj *p, int t,int reg);
+
+/* calculate the actual current offset of an object relativ to the
+ stack-pointer; we use a layout like this:
+ ------------------------------------------------
+ | arguments to this function |
+ ------------------------------------------------
+ | return-address [size=4] |
+ ------------------------------------------------
+ | caller-save registers [size=rsavesize] |
+ ------------------------------------------------
+ | local variables [size=localsize] |
+ ------------------------------------------------
+ | arguments to called functions [size=argsize] |
+ ------------------------------------------------
+ All sizes will be aligned as necessary.
+ For a moving stack-pointer, the stack-pointer will usually point
+ to the bottom of the area for local variables, but will move while
+ arguments are put on the stack.
+
+ This is just an example layout. Other layouts are also possible.
+*/
+
+static long real_offset(struct obj *o)
+{
+ long off = 0;
+ if((o->flags&VAR) && isauto(o->v->storage_class))
+ off=zm2l(o->v->offset);
+// printf("Parameter offset: %d, localsize: %d, rsavesize: %d\n",off,localsize,rsavesize);
+ if (off < 0) {
+ /* function parameter */
+ off = localsize + rsavesize + 4 - off - zm2l(maxalign);
+ }
+ off += pushed;
+ off += notyetpopped;
+ off += zm2l(o->val.vmax);
+ return off;
+}
+
+
+static int isstackparam(struct obj *o)
+{
+ int result=0;
+// if(o->flags&VAR && o->flags® && o->reg==sp)
+// if(o->flags&(VAR|DREFOBJ)==VAR)
+ if((o->flags&VAR) && !(o->flags®))
+ {
+ if(isauto(o->v->storage_class))
+ {
+ long off = zm2l(o->v->offset);
+ if (off < 0)
+ result=1;
+ }
+ }
+ return(result);
+}
+
+/* Convenience function to determine whether we're assigning to 0(r6)
+ and can thus use a more efficient writing sequence. */
+
+int istopstackslot(struct obj *o)
+{
+ if(!o)
+ return(0);
+ if((o->flags&(VAR|REG|DREFOBJ))==VAR && o->v)
+ {
+ if(isauto(o->v->storage_class)
+ && real_offset(o)==0)
+ return(1);
+ }
+ return(0);
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE * f, struct Var *v)
+{
+ char *sec;
+ if (!v->vattr)
+ return 0;
+ sec = strstr(v->vattr, "section(");
+ if (!sec)
+ return 0;
+ sec += strlen("section(");
+ emit(f, "\t.section\t");
+ while (*sec && *sec != ')')
+ emit_char(f, *sec++);
+ emit(f, "\n");
+ if (f)
+ section = SPECIAL;
+ return 1;
+}
+
+/* Returns 1 if the symbol has weak linkage */
+static int isweak(struct Var *v)
+{
+ if (!v->vattr)
+ return 0;
+ if (strstr(v->vattr, "weak"))
+ return (1);
+ return 0;
+}
+
+/* Emits a pointer to a function in a .ctor or .dtor section for automatic setup/cleanup */
+static int ctor_dtor(FILE * f, struct Var *v)
+{
+ int dtor = 0;
+ char *sec;
+ if (!v->vattr)
+ return 0;
+ sec = strstr(v->vattr, "ctor(");
+ if (!sec) {
+ dtor = 1;
+ sec = strstr(v->vattr, "dtor(");
+ }
+ if (!sec)
+ return 0;
+ sec += strlen("ctor(");
+ emit(f, "\t%s.", dtor ? ".dtor .dtor" : ".ctor .ctor");
+ while (*sec && *sec != ')')
+ emit_char(f, *sec++);
+ emit(f, "\n\t.ref\t%s%s\n", idprefix, v->identifier);
+
+ return 1;
+}
+
+
+#define TEMP_TMP 0
+#define TEMP_T1 1
+struct tempobj
+{
+ struct obj o;
+ int reg;
+};
+struct tempobj tempobjs[2];
+
+void cleartempobj(FILE *f, int reg)
+{
+ int i;
+ if(reg==tmp) i=TEMP_TMP;
+ else if(reg==t1) i=TEMP_T1;
+ else return;
+// emit(f,"// clearing %s\n",regnames[reg]);
+
+ tempobjs[i].reg=0;
+}
+
+void settempkonst(FILE *f,int reg,int v)
+{
+ int i;
+ if(reg==tmp) i=TEMP_TMP;
+ else if(reg==t1) i=TEMP_T1;
+ else return;
+ tempobjs[i].reg=reg;
+ tempobjs[i].o.flags=KONST;
+ tempobjs[i].o.val.vlong=v;
+// emit(f,"// set %s to konst %d\n",regnames[reg],v);
+}
+
+
+// Add an adjustment due to postinc / predec to a cached object
+void adjtempobj(FILE *f,int reg,int offset)
+{
+ if(reg<=1)
+ tempobjs[reg].o.val.vlong+=offset;
+}
+
+
+// Store any passing value in tempobj records for optimisation.
+// FIXME - need to figure out VARADR semantics for stored objects.
+void settempobj(FILE *f,int reg,struct obj *o,int offset,int varadr)
+{
+ int i;
+ if(reg==tmp) i=TEMP_TMP;
+ else if(reg==t1) i=TEMP_T1;
+ else return;
+// if(reg==t1)
+// emit(f,"// Setting %s to %x (%x)\n",regnames[reg],o,o->v);
+ tempobjs[i].reg=reg;
+ tempobjs[i].o=*o;
+ tempobjs[i].o.val.vlong+=offset; // Account for any postinc / predec
+ if(varadr)
+ tempobjs[i].o.flags|=VARADR;
+}
+
+
+// Compare a pair of struct obj* for equivalence.
+// The first object should be the "live" object, the second one the cached object."
+int matchobj(FILE *f,struct obj *o1,struct obj *o2,int varadr)
+{
+ int result=1;
+ int flg=o1->flags;
+ if(varadr)
+ flg|=VARADR;
+// emit(f,"// comparing flags %x with %x\n",o1->flags, o2->flags);
+// if((o1->flags&~VARADR)!=(o2->flags&~VARADR))
+ // FIXME - need to figure out VARADR semantics for stored objects.
+ emit(f,"\t\t\t\t\t\t// matchobj comparing flags %d with %d\n",flg,o2->flags);
+ if(flg!=(o2->flags))
+ return(0);
+
+// emit(f,"// comparing regs %d with %d\n",o1->reg, o2->reg);
+ // If the register-based value is being dereferenced we would have to track
+ // the register itself being updated. Unless the value's in tmp using a cached
+ // version isn't a win anyway.
+ if((o1->flags&(REG|DREFOBJ)==REG) && (o1->reg==o2->reg))
+ return(1);
+
+ if(o1->flags&KONST)
+ {
+// emit(f,"\t\t\t\t\t\t// Comparing constants %x with %x\n",o1->val.vlong,o2->val.vlong);
+ if(o1->val.vlong == o2->val.vlong)
+ return(1);
+ else
+ { // Attempt fuzzy matching...
+ int d=o1->val.vlong-o2->val.vlong;
+ // 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.
+ if(count_constantchunks(o1->val.vlong)<4 || count_constantchunks(d)>1)
+ {
+// emit(f,"\t\t\t\t\t\t// Gains from fuzzy matching too small, ignoring.\n");
+ return(0);
+ }
+ else
+ return(2);
+ }
+ }
+
+ if(!(o1->flags&VAR))
+ return(0); // Not a var? Can't do any more.
+
+ if(o1->v==0 || o2->v==0)
+ return(0);
+
+ if(o1->v == o2->v && o1->val.vlong == o2->val.vlong)
+ return(1);
+
+ if(!(flg&VARADR))
+ return(0); // Can only attempt fuzzy matching if this is a varadr
+
+ if(isauto(o1->v->storage_class) && isauto(o2->v->storage_class))
+ {
+ if(DBGMSG)
+ emit(f,"\t\t\t\t\t\t//auto: flags: %x, comparing %d, %d with %d, %d\n",
+ flg,o1->v->offset,o1->val.vlong, o2->v->offset,o2->val.vlong);
+ // Can't fuzzy match between parameters and vars on stack
+ if((o1->v->offset<0 && o2->v->offset>=0) || (o1->v->offset>=0 && o2->v->offset<0))
+ return(0);
+ if(o1->v->offset==o2->v->offset && o1->val.vlong==o2->val.vlong)
+ return(1);
+ if((o1->flags&DREFOBJ) || (o2->flags&DREFOBJ)) // Can't fuzzy match if we're dereferencing.
+ return(0);
+ return(2);
+ }
+
+ if(isextern(o1->v->storage_class) && isextern(o2->v->storage_class))
+ {
+ if(DBGMSG)
+ emit(f,"\t\t\t\t\t\t//extern: comparing %d with %d\n",o1->val.vlong, o2->val.vlong);
+ if(strcmp(o1->v->identifier,o2->v->identifier))
+ return(0);
+ if(o1->val.vlong==o2->val.vlong)
+ return(1);
+ if((o1->flags&DREFOBJ) || (o2->flags&DREFOBJ)) // Can't fuzzy match if we're dereferencing.
+ return(0);
+ return(2);
+ }
+
+ return(0);
+}
+
+
+int matchoffset(struct obj *o,struct obj *o2)
+{
+ if(o->flags&KONST)
+ return(o->val.vlong-o2->val.vlong);
+ if(isextern(o->v->storage_class))
+ return(o->val.vlong-o2->val.vlong);
+ if(isauto(o->v->storage_class))
+// return((o->val.vlong+real_offset(o))-(o2->val.vlong+real_offset(o2)));
+ return((o->val.vlong+o->v->offset)-(o2->val.vlong+o2->v->offset));
+ return(0);
+}
+
+
+void obsoletetempobj(FILE *f,int reg,struct obj *o,int varadr)
+{
+// emit(f,"\t\t\t\t\t// Attempting to obsolete obj\n");
+ if(tempobjs[0].reg==reg && matchobj(f,o,&tempobjs[0].o,varadr))
+ {
+ emit(f,"\t\t\t\t\t\t// Obsoleting tmp\n");
+ cleartempobj(f,tmp);
+ }
+ if(tempobjs[1].reg==reg && matchobj(f,o,&tempobjs[0].o,varadr))
+ {
+ emit(f,"\t\t\t\t\t\t// Obsoleting t1\n");
+ cleartempobj(f,t1);
+ }
+}
+
+
+// Check the tempobj records to see if the value we're interested in can be found in either.
+int matchtempobj(FILE *f,struct obj *o,int varadr,int preferredreg)
+{
+ int hit=0; // Hit will be 1 for an exact match, 2 for a near miss.
+// return(0); // Temporarily disable matching
+ if(tempobjs[0].reg && (hit=matchobj(f,o,&tempobjs[0].o,varadr)))
+ {
+// emit(f,"//match found - tmp\n");
+// printf("//match found - tmp\n");
+ if(hit==1)
+ return(tempobjs[0].reg);
+ else if(hit==2)
+ {
+ int offset=matchoffset(o,&tempobjs[0].o);
+ emit(f,"\t\t\t\t\t\t// Fuzzy match found against tmp.\n");
+ if(preferredreg==tmp)
+ {
+ emit(f,"\tmr\t%s\n",regnames[t1]);
+ emit(f,"\t.liconst\t%d\n",offset);
+ emit(f,"\taddt\t%s\n",regnames[t1]);
+ settempobj(f,t1,&tempobjs[0].o,0,0);
+ settempobj(f,tmp,o,0,varadr);
+ }
+ else
+ {
+ emit(f,"\tmr\t%s\n",regnames[preferredreg]);
+ emit(f,"\t.liconst\t%d\n",offset);
+ settempkonst(f,tmp,offset);
+ emit(f,"\tadd\t%s\n",regnames[preferredreg]);
+ settempobj(f,preferredreg,o,0,varadr);
+ }
+ return(preferredreg);
+// return(tempobjs[0].reg);
+ }
+ else
+ return(0);
+ }
+ else if(tempobjs[1].reg && (hit=matchobj(f,o,&tempobjs[1].o,varadr)))
+ {
+ // Temporarily disable t1 matching. FIXME - keep t1 records more up-to-date.
+// return(0);
+// emit(f,"//match found - t1\n");
+// printf("//match found - t1\n");
+ if(hit==1)
+ return(tempobjs[1].reg);
+ else if(hit==2)
+ {
+ int offset=matchoffset(o,&tempobjs[1].o);
+ if(DBGMSG)
+ emit(f,"\t\t\t\t\t\t//Fuzzy match found, offset: %d (varadr: %d)\n",offset,varadr);
+ // Fuzzy match against t1 - if target is t1 use add, otherwise use addt.
+ emit(f,"\t.liconst\t%d\n",offset);
+ if(preferredreg!=tempobjs[1].reg)
+ {
+ emit(f,"\taddt\t%s\n",regnames[tempobjs[1].reg]);
+ if(preferredreg!=tmp)
+ emit(f,"\tmr\t%s\n",regnames[preferredreg]);
+ settempobj(f,tmp,o,0,0);
+ settempobj(f,preferredreg,o,0,varadr);
+ }
+ else
+ {
+ emit(f,"\tadd\t%s\n",regnames[tempobjs[1].reg]);
+ settempkonst(f,tmp,offset);
+ settempobj(f,tempobjs[1].reg,o,0,varadr);
+ }
+ return(preferredreg);
+ }
+ return(0);
+ }
+ else
+ return(0);
+}
+
+
+int matchtempkonst(FILE *f,int k,int preferredreg)
+{
+// return(0); // Temporarily disable matching
+ struct obj o;
+ o.flags=KONST;
+ o.val.vlong=k;
+ return(matchtempobj(f,&o,0,preferredreg));
+}
+
+
+/* Generates code to store register r into memory object o. */
+
+static void store_reg(FILE * f, int r, struct obj *o, int type)
+{
+ // Need to take different types into account here.
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// Store_reg to type 0x%x, flags 0x%x\n", type,o->flags);
+
+ type &= NQ; // Filter out unsigned, etc.
+ if((type==CHAR || type==SHORT) && isstackparam(o))
+ {
+ emit(f, "\t\t\t\t\t\t// Promoting storage size of stack parameter to int\n");
+ type=INT;
+ }
+
+ switch (type) {
+ case CHAR:
+ emit_prepobj(f, o, type & NQ, tmp, 0);
+ emit(f, "\texg\t%s\n", regnames[r]);
+ emit(f, "\tstbinc\t%s\t//WARNING - pointer / reg not restored, might cause trouble!\n", regnames[r]);
+ cleartempobj(f,tmp);
+ cleartempobj(f,r);
+ break;
+ case SHORT:
+ emit_prepobj(f, o, type & NQ, tmp, 0);
+ emit(f, "\texg\t%s\n", regnames[r]);
+ emit(f, "\thlf\n\tst\t%s\n", regnames[r]);
+ cleartempobj(f,tmp);
+ cleartempobj(f,r);
+ break;
+ case INT:
+ case LONG:
+ case POINTER:
+ // if o is a reg, can store directly.
+ if ((o->flags & (REG | DREFOBJ)) == (REG | DREFOBJ)) {
+ emit(f, "\tmt\t%s\n", regnames[r]);
+ emit(f, "\tst\t%s\n", regnames[o->reg]);
+// settempobj(f,r,o,0,0);
+ if((type&NQ)!=INT || (type & VOLATILE) || (type & PVOLATILE))
+ {
+ emit(f,"\t// Volatile, or not int - not caching\n");
+ cleartempobj(f,r);
+ }
+ else
+ settempobj(f,r,o,0,0); // FIXME - is this correct?
+ settempobj(f,tmp,o,0,0); // FIXME - is this correct?
+ } else {
+ if(o->flags & DREFOBJ) { // Can't use the offset / stmpdec trick for dereferenced objects.
+ // FIXME, not strictly true - could use it for dereferenced constants
+ emit_prepobj(f, o, type & NQ, tmp, 0);
+ emit(f, "\texg\t%s\n", regnames[r]);
+ emit(f, "\tst\t%s\n", regnames[r]);
+ if(r==t1 || (o->am && o->am->disposable))
+ emit(f, "\t\t\t\t\t\t// WARNING - Object is disposable, not bothering to undo exg - check correctness\n");
+ else
+ emit(f, "\texg\t%s\n", regnames[r]);
+ cleartempobj(f,tmp);
+ cleartempobj(f,r);
+ }
+ else {
+ emit_prepobj(f, o, type & NQ, tmp, 4); // stmpdec predecrements, so need to add 4!
+ emit(f, "\tstmpdec\t%s\n \t\t\t\t\t\t// WARNING - check that 4 has been added.\n", regnames[r]);
+ adjtempobj(f,tmp,-4);
+// cleartempobj(f,tmp);
+ if((type&NQ)!=INT || (type & VOLATILE) || (type & PVOLATILE))
+ {
+ emit(f,"\t// Volatile, or not int - not caching\n");
+ cleartempobj(f,r);
+ }
+ else
+ settempobj(f,r,o,0,0); // FIXME - is this correct?
+ }
+ }
+ break;
+ case LLONG:
+ if ((o->flags & (REG | DREFOBJ)) == (REG | DREFOBJ)) {
+ emit_prepobj(f, o, type & NQ, tmp, 0);
+ printf("store_reg: storing long long to dereferenced register\n");
+ emit(f,"//FIXME - need to store 64-bits\n");
+ ierror(0);
+ }
+ else {
+ //
+ printf("store_reg: storing long long in %s to reg\n",regnames[r]);
+ ierror(0);
+ }
+ break;
+ default:
+ printf("store_reg: unhandled type 0x%x\n", type);
+ ierror(0);
+ break;
+ }
+}
+
+
+/* Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+ zumax p;
+ int ln = 1;
+ p = ul2zum(1L);
+ while (ln <= 32 && zumleq(p, x)) {
+ if (zumeqto(x, p))
+ return ln;
+ ln++;
+ p = zumadd(p, p);
+ }
+ return 0;
+}
+
+
+static int availreg()
+{
+ int i;
+ for(i=FIRST_GPR+RESERVED_GPRS;i<(LAST_GPR-1);++i)
+ if(regs[i]==0)
+ return(i);
+ return(0);
+}
+
+
+static struct IC *preload(FILE *, struct IC *,int stacksubst);
+
+static void function_top(FILE *, struct Var *, long);
+static int function_bottom(FILE * f, struct Var *, long,int);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define involvesreg(x) ((p->x.flags&(REG))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static int q1reg, q2reg, zreg;
+
+static char *ccs[] = { "EQ", "NEQ", "SLT", "GE", "LE", "SGT", "EX", "" };
+static char *logicals[] = { "or", "xor", "and" };
+
+static char *arithmetics[] = { "shl", "shr", "add", "sub", "mul", "(div)", "(mod)" };
+
+/* Does some pre-processing like fetching operands from memory to
+ registers etc. */
+static struct IC *preload(FILE * f, struct IC *p,int stacksubst)
+{
+ int r;
+
+ if(stacksubst)
+ {
+ if(istopstackslot(&p->q1))
+ {
+ p->q1.reg=sp;
+ p->q1.flags|=REG|DREFOBJ;
+ }
+
+ if(istopstackslot(&p->q2))
+ {
+ p->q2.reg=sp;
+ p->q2.flags|=REG|DREFOBJ;
+ }
+
+ if(istopstackslot(&p->z))
+ {
+ p->z.reg=sp;
+ p->z.flags|=REG|DREFOBJ;
+ }
+ }
+
+ if (involvesreg(q1))
+ q1reg = p->q1.reg;
+ else
+ q1reg = 0;
+
+ if (involvesreg(q2))
+ q2reg = p->q2.reg;
+ else
+ q2reg = 0;
+
+ if (isreg(z)) {
+ zreg = p->z.reg;
+ } else {
+ if (ISFLOAT(ztyp(p)))
+ zreg = f1;
+ else
+ zreg = t1;
+ }
+
+ return p;
+}
+
+/* Determine whether the register we're about to write to will merely be passed to SetReturn.
+ If so, return 1, and convert the SetReturn IC to NOP */
+int next_setreturn(struct IC *p,int reg)
+{
+ int result=0;
+ struct IC *p2=p->next;
+ while(p2 && p2->code==FREEREG)
+ p2=p2->next;
+ if(p2 && p2->code==SETRETURN && (p2->q1.flags&(REG|DREFOBJ))==REG && p2->q1.reg==reg)
+ {
+ p2->code=NOP;
+ result=1;
+ }
+ return(result);
+}
+
+
+int consecutiveaccess(struct IC *p,struct IC *p2)
+{
+ if(!p || !p2)
+ return(0);
+// printf("Flags %x, %x\n",p->z.flags,p2->z.flags);
+ if(((p->z.flags&(VAR|DREFOBJ))==VAR) && ((p2->z.flags&(VAR|DREFOBJ))==VAR))
+ {
+ int result=real_offset(&p2->z)-real_offset(&p->z);
+// printf("Got two vars\n");
+ if(strcmp(p->z.v->identifier,p2->z.v->identifier))
+ return(0);
+ if(isstatic(p->z.v->storage_class) && isstatic(p->z.v->storage_class))
+ {
+// printf("Both static - dif %d\n",result);
+ return(result);
+ }
+ if(isextern(p->z.v->storage_class) && isextern(p->z.v->storage_class))
+ {
+// printf("Both extern - dif %d\n",result);
+ return(result);
+ }
+ }
+ return(0);
+}
+
+/* save the result (in temp) into p->z */
+/* Guaranteed not to touch t1/t2 unless nominated */
+/* or followed by a SetReturn IC. */
+void save_temp(FILE * f, struct IC *p, int treg)
+{
+ int type = ztyp(p) & NQ;
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// (save temp)");
+
+ if (isreg(z)) {
+ int target=p->z.reg;
+ if(DBGMSG)
+ emit(f, "isreg\n");
+ if(next_setreturn(p,target))
+ target=t1;
+ emit(f, "\tmr\t%s\n", regnames[target]);
+ } else {
+ if ((p->z.flags & DREFOBJ) && (p->z.flags & REG))
+ treg = p->z.reg;
+ else if(isstackparam(&p->z) && !(p->z.flags & DREFOBJ))
+ type=INT;
+
+ if(DBGMSG)
+ emit(f, "store type %x\n",type);
+
+ switch (type) {
+ case CHAR:
+ if (p->z.am && p->z.am->type == AM_POSTINC)
+ {
+ emit(f, "\tstbinc\t%s\n", regnames[treg]);
+ adjtempobj(f,treg,1);
+ }
+ else if ((p->z.am && p->z.am->disposable)
+ || (treg == t1))
+ {
+ emit(f, "\tstbinc\t%s\n\t\t\t\t\t\t//Disposable, postinc doesn't matter.\n", regnames[treg]);
+ adjtempobj(f,treg,1);
+ }
+ else
+ emit(f, "\tbyt\n\tst\t%s\n", regnames[treg]);
+ break;
+ case SHORT:
+ emit(f, "\thlf\n\tst\t%s\n", regnames[treg]);
+ break;
+ case INT:
+ case LONG:
+ case POINTER:
+// // Would need to adjust the pointer at the setup stage since we're predecrementing
+// if (consecutiveaccess(p,p->next)==-4 || (p->z.am && p->z.am->type == AM_PREDEC))
+// {
+// emit(f, "\tstdec\t%s\n", regnames[treg]);
+// adjtempobj(f,treg,-4);
+// }
+ if (consecutiveaccess(p,p->next)==4 || (p->z.am && p->z.am->type == AM_POSTINC))
+ {
+ emit(f, "\tstinc\t%s\n", regnames[treg]);
+ adjtempobj(f,treg,4);
+ }
+ else
+ emit(f, "\tst\t%s\n", regnames[treg]);
+ break;
+ default:
+ printf("save_temp - type %d not yet handled\n", ztyp(p));
+ emit(f,"\t\t\t\t\t\t// FIXME - save_temp doesn't support size\n");
+ break;
+ }
+ }
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//save_temp done\n");
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE * f, struct IC *p)
+{
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// (save result) ");
+ if (isreg(z)) {
+ if(DBGMSG)
+ emit(f, "// isreg\n");
+ if (p->z.reg != zreg)
+ {
+ emit(f, "\tmt\t%s\n\tmr\t%s\n", regnames[zreg], regnames[p->z.reg]);
+ settempobj(f,tmp,&p->z,0,0);
+ settempobj(f,p->z.reg,&p->z,0,0);
+ }
+ }
+ else
+ {
+ emit(f, "// not reg\n");
+ store_reg(f,zreg,&p->z,ztyp(p));
+ }
+ return;
+}
+
+#include "addressingmodes.c"
+#include "tempregs.c"
+#include "inlinememcpy.c"
+#include "libcalls.c"
+
+/* generates the function entry code */
+static void function_top(FILE * f, struct Var *v, long offset)
+{
+ int i;
+ int regcount = 0;
+
+ cleartempobj(f,tmp);
+ cleartempobj(f,t1);
+
+ if(DBGMSG)
+ {
+ emit(f, "\t//registers used:\n");
+ for (i = FIRST_GPR+RESERVED_GPRS; i <= LAST_GPR; ++i) {
+ emit(f, "\t\t//%s: %s\n", regnames[i], regused[i] ? "yes" : "no");
+ if (regused[i] && (i >= (FIRST_GPR+SCRATCH_GPRS+RESERVED_GPRS)) && (i <= LAST_GPR - 2))
+ ++regcount;
+ }
+ }
+
+// Emit ctor / dtor tables
+ ctor_dtor(f, v);
+
+ rsavesize = 0;
+ if (!special_section(f, v)) {
+ emit(f, "\t.section\t.text.%x\n", sectionid);
+ section=CODE;
+ ++sectionid;
+ }
+ if (v->storage_class == EXTERN) {
+ if ((v->flags & (INLINEFUNC | INLINEEXT)) != INLINEFUNC) {
+ if (isweak(v))
+ emit(f, "\t.weak\t%s%s\n", idprefix, v->identifier);
+ else
+ emit(f, "\t.global\t%s%s\n", idprefix, v->identifier);
+ }
+ emit(f, "%s%s:\n", idprefix, v->identifier);
+ } else
+ emit(f, "%s%ld:\n", labprefix, zm2l(v->offset));
+
+ if (regcount < 3) {
+ emit(f, "\tstdec\t%s\n", regnames[sp]);
+ for (i = FIRST_GPR + SCRATCH_GPRS; i <= LAST_GPR - 3; ++i) {
+ if (regused[i] && !regscratch[i]) {
+ emit(f, "\tmt\t%s\n\tstdec\t%s\n", regnames[i], regnames[sp]);
+ rsavesize += 4;
+ }
+ }
+ } else {
+ emit(f, "\texg\t%s\n\tstmpdec\t%s\n", regnames[sp], regnames[sp]);
+ for (i = FIRST_GPR + SCRATCH_GPRS; i <= LAST_GPR - 3; ++i) {
+ if (regused[i] && !regscratch[i]) {
+ emit(f, "\tstmpdec\t%s\n", regnames[i]);
+ rsavesize += 4;
+ }
+ }
+ emit(f, "\texg\t%s\n", regnames[sp]);
+ }
+
+ // FIXME - Allow the stack to float, in the hope that we can use stdec to adjust it.
+
+ if ((offset == 4) && optsize)
+ emit(f, "\tstdec\tr6\t// shortest way to decrement sp by 4\n");
+ else if (offset) {
+ emit_constanttotemp(f, -offset);
+ emit(f, "\tadd\t%s\n", regnames[sp]);
+ }
+}
+
+/* generates the function exit code */
+/* Returns 1 if tail code was generated. */
+static int function_bottom(FILE * f, struct Var *v, long offset,int firsttail)
+{
+ int i;
+ int tail=0;
+
+ int regcount = 0;
+ for (i = FIRST_GPR + SCRATCH_GPRS + RESERVED_GPRS; i <= LAST_GPR - 3; ++i) {
+ if (regused[i] && !regscratch[i])
+ ++regcount;
+ }
+
+ if ((offset == 4) && optsize)
+ emit(f, "\tldinc\t%s\t// shortest way to add 4 to sp\n", regnames[sp]);
+ else if (offset) {
+ emit_constanttotemp(f, -offset); // Negative range extends one integer further than positive range.
+ emit(f, "\tsub\t%s\n", regnames[sp]);
+ }
+
+ if(optsize) // If we're optimising for size we can potentially save some bytes in the function tails.
+ {
+ if(regcount)
+ {
+ /* We have to restore some registers. Jump into the tail code at the appropriate place. */
+ if(regcount<(5-SCRATCH_GPRS) || !firsttail)
+ {
+ emit(f,"\t.lipcrel\t.functiontail, %d\n",((5-SCRATCH_GPRS)-regcount)*2);
+ emit(f,"\tadd\t%s\n\n",regnames[pc]);
+ }
+ if(firsttail)
+ {
+ /* This is the first time we've needed to restore registers - generate tail code */
+ emit(f,".functiontail:\n");
+ for (i = LAST_GPR - 3; i >= FIRST_GPR + SCRATCH_GPRS; --i) {
+ if (!regscratch[i])
+ emit(f, "\tldinc\t%s\n\tmr\t%s\n\n", regnames[sp], regnames[i]);
+ }
+ emit(f, "\tldinc\t%s\n\tmr\t%s\n\n", regnames[sp], regnames[pc]);
+ if(f)
+ tail=1; /* Higher optimisation levels do a dummy run with null file */
+ }
+ }
+ else
+ {
+ /* Didn't need to preserve any registers, just restore PC */
+ emit(f, "\tldinc\t%s\n\tmr\t%s\n\n", regnames[sp], regnames[pc]);
+ }
+ }
+ else
+ {
+ for (i = LAST_GPR - 3; i >= FIRST_GPR + SCRATCH_GPRS; --i) {
+ if (regused[i] && !regscratch[i])
+ emit(f, "\tldinc\t%s\n\tmr\t%s\n\n", regnames[sp], regnames[i]);
+ }
+ emit(f, "\tldinc\t%s\n\tmr\t%s\n\n", regnames[sp], regnames[pc]);
+ }
+ return(tail);
+}
+
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+int init_cg(void)
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign = l2zm(4L);
+ char_bit = l2zm(8L);
+ stackalign = l2zm(4);
+
+ flag_832_bigendian=0;
+ if(g_flags[FLAG_BE]&USEDFLAG)
+ flag_832_bigendian=1;
+ else if(!g_flags[FLAG_BE]&USEDFLAG)
+ printf("Neither -eb nor -el specified - defaulting to little-endian\n");
+
+#ifndef V09G
+ clist_copy_stack=0;
+ clist_copy_static=0;
+ clist_copy_pointer=0;
+#endif
+
+ // We have full load-store align, so in size mode we can pack data more tightly...
+
+ for (i = 0; i <= MAX_TYPE; i++) {
+ sizetab[i] = l2zm(msizetab[i]);
+ align[i] = optsize ? 1 : l2zm(malign[i]);
+
+// Can't align everything to 4 bytes for speed without messing up struct packing. Is there a better way?
+// align[i] = optspeed ? 4 : (optsize ? 1 : l2zm(malign[i]));
+// align[i] = l2zm(malign[i]);
+ }
+
+ regnames[0] = "noreg";
+ for (i = FIRST_GPR; i <= LAST_GPR - 1; i++) {
+ regnames[i] = mymalloc(5);
+ sprintf(regnames[i], "r%d", i - FIRST_GPR);
+ regsize[i] = l2zm(4L);
+ regtype[i] = <yp;
+ regsa[i] = 0;
+ }
+ regnames[i] = mymalloc(5);
+ sprintf(regnames[i], "tmp");
+ regsize[i] = l2zm(4L);
+ regtype[i] = <yp;
+ regsa[i] = 1;
+ for (i = FIRST_FPR; i <= LAST_FPR; i++) {
+ regnames[i] = mymalloc(10);
+ sprintf(regnames[i], "fpr%d", i - FIRST_FPR);
+ regsize[i] = l2zm(8L);
+ regtype[i] = &ldbl;
+ }
+
+ /* Use multiple ccs. */
+ multiple_ccs = 0;
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR] = l2zm(-128L);
+ t_min[SHORT] = l2zm(-32768L);
+ t_min[INT] = zmsub(l2zm(-2147483647L), l2zm(1L));
+ t_min[LONG] = t_min(INT);
+ t_min[LLONG] = zmlshift(l2zm(1L), l2zm(63L));
+ t_min[MAXINT] = t_min(LLONG);
+ t_max[CHAR] = ul2zum(127L);
+ t_max[SHORT] = ul2zum(32767UL);
+ t_max[INT] = ul2zum(2147483647UL);
+ t_max[LONG] = t_max(INT);
+ t_max[LLONG] = zumrshift(zumkompl(ul2zum(0UL)), ul2zum(1UL));
+ t_max[MAXINT] = t_max(LLONG);
+ tu_max[CHAR] = ul2zum(255UL);
+ tu_max[SHORT] = ul2zum(65535UL);
+ tu_max[INT] = ul2zum(4294967295UL);
+ tu_max[LONG] = t_max(UNSIGNED | INT);
+ tu_max[LLONG] = zumkompl(ul2zum(0UL));
+ tu_max[MAXINT] = t_max(UNSIGNED | LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ /* This is not optimal but simple. */
+ tmp = FIRST_GPR + 8;
+ pc = FIRST_GPR + 7;
+ sp = FIRST_GPR + 6;
+ t1 = FIRST_GPR; // r0, also return register.
+ t2 = FIRST_GPR + 1;
+// f1=FIRST_FPR;
+// f2=FIRST_FPR+1;
+
+ for (i = FIRST_GPR; i <= LAST_GPR; i++)
+ regscratch[i] = 0;
+ for (i = FIRST_FPR; i <= LAST_FPR; i++)
+ regscratch[i] = 0;
+
+ regsa[FIRST_GPR] = 1; // Allocate the return register
+ regsa[t1] = 1;
+ regsa[t2] = 0;
+ regsa[sp] = 1;
+ regsa[pc] = 1;
+ regsa[tmp] = 1;
+ regscratch[FIRST_GPR] = 0;
+ for(i=FIRST_GPR+RESERVED_GPRS;i<(FIRST_GPR+RESERVED_GPRS+SCRATCH_GPRS);++i)
+ regscratch[i] = 1;
+ regscratch[sp] = 0;
+ regscratch[pc] = 0;
+
+ target_macros = marray;
+
+ return 1;
+}
+
+void init_db(FILE * f)
+{
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+/* A pointer MUST be returned in a register. The code-generator */
+/* has to simulate a pseudo register if necessary. */
+{
+ if (ISFLOAT(t->flags))
+ return 0;
+ if (ISSTRUCT(t->flags) || ISUNION(t->flags))
+ return 0;
+ if (zmleq(szof(t), l2zm(4L)))
+ return FIRST_GPR;
+ else
+ return 0;
+}
+
+int reg_pair(int r, struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+ register r */
+int cost_savings(struct IC *p, int r, struct obj *o)
+{
+ int c = p->code;
+ if(o->v && isextern(o->v->storage_class)) // Externs are particularly costly due to the ldinc r7 shuffle
+ return(o->flags & DREFOBJ ? 5 : 3);
+ if (o->flags & VKONST) {
+ if (isextern(o->flags) || isstatic(o->flags))
+ return 2;
+ else {
+ struct obj *o2 = &o->v->cobj;
+ int c = count_constantchunks(o2->val.vmax);
+ return c - 1;
+ }
+ }
+ if (o->flags & DREFOBJ)
+ return 2;
+ if (c == SETRETURN)// && r == p->z.reg && !(o->flags & DREFOBJ))
+ return 1;
+ if (c == GETRETURN)// && r == p->q1.reg && !(o->flags & DREFOBJ))
+ return 1;
+ return 1;
+}
+
+int regok(int r, int t, int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if (r == 0)
+ return 0;
+ t &= NQ;
+ if (ISFLOAT(t) && r >= FIRST_FPR && r <= LAST_FPR)
+ return 1;
+ if (t == POINTER && r >= FIRST_GPR && r <= LAST_GPR)
+ return 1;
+ if (t >= CHAR && t <= LONG && r >= FIRST_GPR && r <= LAST_GPR)
+ return 1;
+ return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c = p->code;
+ if ((p->q1.flags & DREFOBJ) || (p->q2.flags & DREFOBJ)
+ || (p->z.flags & DREFOBJ))
+ return 1;
+ if ((c == DIV || c == MOD) && !isconst(q2))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o, int t, int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* On the PowerPC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op = o & NQ, tp = t & NQ;
+ if ((op == INT || op == LONG || op == POINTER)
+ && (tp == INT || tp == LONG || tp == POINTER))
+ return 0;
+ if (op == DOUBLE && tp == LDOUBLE)
+ return 0;
+ if (op == LDOUBLE && tp == DOUBLE)
+ return 0;
+ return 1;
+}
+
+void gen_ds(FILE * f, zmax size, struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ if (newobj && section != SPECIAL)
+ emit(f, "%ld\n", zm2l(size));
+ else
+ emit(f, "\t.space\t%ld\n", zm2l(size));
+ newobj = 0;
+}
+
+
+/* This function has to make sure the next data is
+ aligned to multiples of <align> bytes.
+ If the speed optimisation flag is set, always align
+ to four bytes. */
+void gen_align(FILE * f, zmax align)
+{
+ if(optspeed)
+ emit(f,"\t.align\t4\n");
+ else if (zm2l(align) > 1)
+ emit(f, "\t.align\t%d\n", align);
+}
+
+void gen_var_head(FILE * f, struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;
+ char *sec;
+ if (v->clist)
+ constflag = is_const(v->vtyp);
+ if (v->storage_class == STATIC) {
+ if (ISFUNC(v->vtyp->flags))
+ return;
+ if (!special_section(f, v)) {
+ if (v->clist && (!constflag)) { // || (g_flags[2] & USEDFLAG))
+// && section != DATA) {
+ emit(f, "%s.%x\n",dataname,sectionid);
+ ++sectionid;
+ if (f)
+ section = DATA;
+ }
+ if (v->clist && constflag) { // && !(g_flags[2] & USEDFLAG)
+// && section != RODATA) {
+ emit(f, "%s.%x\n",rodataname,sectionid);
+ ++sectionid;
+ if (f)
+ section = RODATA;
+ }
+ if (!v->clist) { // && section != BSS) {
+ emit(f, "%s.%x\n",bssname,sectionid);
+ ++sectionid;
+ if (f)
+ section = BSS;
+ }
+ }
+ if (v->clist || section == SPECIAL) {
+ gen_align(f, falign(v->vtyp));
+ emit(f, "%s%ld:\n", labprefix, zm2l(v->offset));
+ } else {
+ gen_align(f, falign(v->vtyp));
+ emit(f, "\t.lcomm\t%s%ld,", labprefix, zm2l(v->offset));
+ }
+ newobj = 1;
+ }
+ if (v->storage_class == EXTERN) {
+// emit(f, "\t.global\t%s%s\n", idprefix, v->identifier);
+ if (v->flags & (DEFINED | TENTATIVE)) {
+ if (!special_section(f, v)) {
+ if (v->clist && (!constflag)) { // || (g_flags[2] & USEDFLAG))
+// && section != DATA) {
+ emit(f, "%s.%x\n",dataname,sectionid);
+ ++sectionid;
+ if (f)
+ section = DATA;
+ }
+ if (v->clist && constflag) { // && !(g_flags[2] & USEDFLAG)
+// && section != RODATA) {
+ emit(f, "%s.%x\n",rodataname,sectionid);
+ ++sectionid;
+ if (f)
+ section = RODATA;
+ }
+ if (!v->clist) { // && section != BSS) {
+ emit(f, "%s.%x\n",bssname,sectionid);
+ ++sectionid;
+ if (f)
+ section = BSS;
+ }
+ }
+ if (v->clist || section == SPECIAL) {
+ gen_align(f, falign(v->vtyp));
+ if (isweak(v))
+ emit(f, "\t.weak\t%s%s\n", idprefix, v->identifier);
+ else
+ emit(f, "\t.global\t%s%s\n", idprefix, v->identifier);
+ emit(f, "%s%s:\n", idprefix, v->identifier);
+ } else {
+ gen_align(f, falign(v->vtyp));
+ if (isweak(v))
+ emit(f, "\t.weak\t%s%s\n", idprefix, v->identifier);
+ else {
+ emit(f, "\t.global\t%s%s\n", idprefix, v->identifier);
+ emit(f, "\t.comm\t%s%s,", idprefix, v->identifier);
+ }
+ }
+ newobj = 1;
+ }
+ }
+}
+
+void gen_dc(FILE * f, int t, struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ if (!p->tree) {
+ switch (t & NQ) {
+ case CHAR:
+ emit(f, "\t.byte\t");
+ break;
+ case SHORT:
+ emit(f, "\t.short\t");
+ break;
+ case LONG:
+ case INT:
+ case MAXINT:
+ case POINTER:
+ emit(f, "\t.int\t");
+ break;
+ case LLONG:
+ emit(f, "//FIXME - unsupported type\n");
+ emit(f, "\t.long\t");
+// ierror(0);
+ break;
+ default:
+ printf("gen_dc: unsupported type 0x%x\n", t);
+ ierror(0);
+ }
+ emitval(f, &p->val, t & NU);
+ emit(f, "\n");
+
+#if 0
+ if (ISFLOAT(t)) {
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+ ip = (unsigned char *)&p->val.vdouble;
+ emit(f, "0x%02x%02x%02x%02x", ip[0], ip[1], ip[2], ip[3]);
+ if ((t & NQ) != FLOAT) {
+ emit(f, ",0x%02x%02x%02x%02x", ip[4], ip[5], ip[6], ip[7]);
+ }
+ } else {
+ emitval(f, &p->val, t & NU);
+ }
+#endif
+ } else {
+ struct obj *o = &p->tree->o;
+ emit(f, "\t\t\t\t\t\t// Declaring from tree\n");
+ if (isextern(o->v->storage_class)) {
+ emit(f, "\t\t\t\t\t\t// extern (offset %d)\n", o->val.vmax);
+ if (o->val.vmax)
+ emit(f, "\t.ref\t_%s, %d\n", o->v->identifier, o->val.vmax);
+ else
+ emit(f, "\t.ref\t_%s\n", o->v->identifier);
+ } else if (isstatic(o->v->storage_class)) {
+ emit(f, "\t\t\t\t\t\t// static\n");
+ if(o->val.vlong)
+ emit(f, "\t.ref\t%s%d,%d\n", labprefix, zm2l(o->v->offset),o->val.vlong);
+ else
+ emit(f, "\t.ref\t%s%d\n", labprefix, zm2l(o->v->offset));
+ } else {
+ printf("error: GenDC (tree) - unknown storage class 0x%x!\n", o->v->storage_class);
+ }
+ }
+ newobj = 0;
+}
+
+
+/* Return 1 if any of p's operands uses predec or postinc addressing mode */
+int check_am(struct IC *p)
+{
+ if(p->q1.am && (p->q1.am->type==AM_POSTINC || p->q1.am->type==AM_PREDEC))
+ return(1);
+ if(p->q2.am && (p->q2.am->type==AM_POSTINC || p->q2.am->type==AM_PREDEC))
+ return(1);
+ if(p->z.am && (p->z.am->type==AM_POSTINC || p->z.am->type==AM_PREDEC))
+ return(1);
+ return(0);
+}
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE * f, struct IC *p, struct Var *v, zmax offset)
+/* The main code-generation. */
+{
+ static int idemp = 0;
+ static int firsttail=1;
+ int reversecmp=0;
+ int c, t, i;
+ struct IC *m;
+ argsize = 0;
+ // if(DEBUG&1)
+
+ if(!p)
+ printf("(gen_code called with null IC list?)\n");
+
+ for (c = 1; c <= MAXR; c++)
+ regs[c] = regsa[c];
+ pushed = 0;
+ notyetpopped = 0;
+
+#if 0
+ if (!idemp) {
+ sectionid = 0;
+ if (p && p->file) {
+ int v;
+ char *c = p->file;
+ idemp = 1;
+ while (v = *c++) {
+ sectionid <<= 3;
+ sectionid ^= v;
+ }
+ printf("Created section ID %x\n",sectionid);
+ }
+ else
+ printf("No sectionid created (%x, %x)\n",p,p ? p->file : 0);
+ }
+#endif
+
+ for (m = p; m; m = m->next) {
+ c = m->code;
+ t = m->typf & NU;
+ if (c == ALLOCREG) {
+ regs[m->q1.reg] = 1;
+ continue;
+ }
+ if (c == FREEREG) {
+ regs[m->q1.reg] = 0;
+ continue;
+ }
+
+ /* convert MULT/DIV/MOD with powers of two */
+ // Perversely, mul is faster than shifting on 832, so we only want to do this for div.
+ // FIXME - we can do this for signed values too.
+ if ((t & NQ) <= LONG && (m->q2.flags & (KONST | DREFOBJ)) == KONST && (t & NQ) <= LONG
+ && (((c == DIV || c == MOD) && (t & UNSIGNED)))) {
+ eval_const(&m->q2.val, t);
+ i = pof2(vmax);
+ if (i) {
+ if (c == MOD) {
+ vmax = zmsub(vmax, l2zm(1L));
+ m->code = AND;
+ } else {
+ vmax = l2zm(i - 1);
+ if (c == DIV)
+ m->code = RSHIFT;
+ else
+ m->code = LSHIFT;
+ }
+ c = m->code;
+ gval.vmax = vmax;
+ eval_const(&gval, MAXINT);
+ if (c == AND) { // FIXME - why?
+ insert_const(&m->q2.val, t);
+ } else {
+ insert_const(&m->q2.val, INT);
+ p->typf2 = INT;
+ }
+ }
+ }
+ }
+
+ for (c = 1; c <= MAXR; c++) {
+ if (regsa[c] || regused[c]) {
+ BSET(regs_modified, c);
+ }
+ }
+ localsize = (zm2l(offset) + 3) / 4 * 4;
+
+// printf("\nSeeking addressing modes for function %s\n",v->identifier);
+ find_addressingmodes(p);
+
+ function_top(f, v, localsize);
+// printf("%s:\n",v->identifier);
+
+ for (; p; p = p->next) {
+// printic(stdout,p);
+ c = p->code;
+ t = q1typ(p);
+
+ if (c == NOP) {
+ p->z.flags = 0;
+ continue;
+ }
+ if (c == ALLOCREG) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// allocreg %s\n", regnames[p->q1.reg]);
+ regs[p->q1.reg] = 1;
+ continue;
+ }
+ if (c == FREEREG) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// freereg %s\n", regnames[p->q1.reg]);
+ regs[p->q1.reg] = 0;
+ continue;
+ }
+ if (c == LABEL) {
+ int i;
+ emit(f, "%s%d: # \n", labprefix, t);
+ cleartempobj(f,tmp); // Can't carry temporary context past a label
+ cleartempobj(f,t1);
+ continue;
+ }
+
+ if (DBGMSG && p->file)
+ emit(f, "\n\t\t\t\t\t\t//%s, line %d\n", p->file, p->line);
+ if(p->q1.am && p->q1.am->disposable)
+ emit(f, "\t\t\t\t\t\t// Q1 disposable\n");
+ if(p->q2.am && p->q2.am->disposable)
+ emit(f, "\t\t\t\t\t\t// Q2 disposable\n");
+ if(p->z.am && p->z.am->disposable)
+ emit(f, "\t\t\t\t\t\t// Z disposable\n");
+
+ // OK
+ if (c == BRA) {
+ if(0) // FIXME - could duplicate function tail here. Perhaps do it depending on number of saved registers?
+ function_bottom(f, v, localsize, 0);
+ else
+ emit_pcreltotemp(f, labprefix, t);
+ emit(f, "\tadd\t%s\n", regnames[pc]);
+ continue;
+ }
+ // OK
+ if (c >= BEQ && c < BRA) {
+ if(reversecmp)
+ {
+ switch(c)
+ {
+ case BLT:
+ c=BGT;
+ break;
+ case BLE:
+ c=BGE;
+ break;
+ case BGT:
+ c=BLT;
+ break;
+ case BGE:
+ c=BLE;
+ break;
+ }
+ }
+ emit(f, "\tcond\t%s\n",ccs[c - BEQ]);
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//conditional branch %s\n",reversecmp ? "reversed" : "regular");
+ reversecmp=0;
+ emit_pcreltotemp(f, labprefix, t); // FIXME - double-check that we shouldn't include an offset here.
+ emit(f, "\t\tadd\tr7\n");
+ continue;
+ }
+ // Investigate - but not currently seeing it used.
+ if (c == MOVETOREG) {
+ emit(f, "\t\t\t\t\t\t//CHECKME movetoreg\n");
+ emit_objtoreg(f, &p->q1, ztyp(p),zreg);
+ continue;
+ }
+ // Investigate - but not currently seeing it used.
+ if (c == MOVEFROMREG) {
+ emit(f, "\t\t\t\t\t\t//CHECKME movefromreg\n");
+ store_reg(f, p->q1.reg, &p->z, regtype[p->q1.reg]->flags);
+ continue;
+ }
+ // Reject types we can't handle - anything beyond a pointer and chars with more than 1 byte.
+// if ((c == PUSH)
+// && ((t & NQ) > POINTER || ((t & NQ) == CHAR && zm2l(p->q2.val.vmax) != 1))) {
+// printf("Pushing a type we don't yet handle: 0x%x\n", t);
+// ierror(0);
+// }
+
+ if ((c == ASSIGN) && ((t & NQ) > UNION)) {
+ printf("Assignment of a type we don't yet handle: 0x%x\n", t);
+ ierror(0);
+ }
+
+ // Avoid stack top slot trickery if the operation involves pushing operands to the stack
+ if(c==DIV || c==MOD ||
+ ((c==ASSIGN || c==PUSH) && ((t & NQ) > POINTER || ((t & NQ) == CHAR && zm2l(p->q2.val.vmax) != 1))))
+ p = preload(f, p, 0); // Setup zreg, etc.
+ else
+ p = preload(f, p, 1); // Setup zreg, etc.
+
+ c = p->code;
+
+ if (c == SUBPFP)
+ c = SUB;
+ if (c == ADDI2P)
+ c = ADD;
+ if (c == SUBIFP)
+ c = SUB;
+
+// emit(f, "// code 0x%x, q1->v: %x\n", c,&p->q1.v);
+// if(p->prev && matchobj(f,&p->q1,&p->prev->q1))
+// emit(f, "// Matching objs found\n", p->prev->code,&p->prev->q1.v);
+
+ if (c == CONVERT) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//FIXME convert\n");
+ if (ISFLOAT(q1typ(p)) || ISFLOAT(ztyp(p))) {
+ printf("Float not yet supported\n");
+ ierror(0);
+ }
+ if (sizetab[q1typ(p) & NQ] < sizetab[ztyp(p) & NQ]) {
+ int shamt = 0;
+ if(DBGMSG)
+ emit(f,"\t\t\t\t\t\t//Converting to wider type...\n");
+ switch (q1typ(p) & NU) {
+ case CHAR | UNSIGNED:
+ case SHORT | UNSIGNED:
+ if(DBGMSG)
+ emit(f,"\t\t\t\t\t\t//But unsigned, so no need to extend\n");
+
+ if(involvesreg(z)) {
+ emit_prepobj(f, &p->z, ztyp(p), zreg, 0);
+ emit_objtoreg(f, &p->q1, q1typ(p), tmp);
+ save_temp(f, p, zreg);
+ // WARNING - might need to invalidate temp objects here...
+ } else {
+ emit_objtoreg(f, &p->q1, q1typ(p), zreg);
+ save_result(f, p);
+ // WARNING - might need to invalidate temp objects here...
+ }
+ break;
+ case CHAR:
+ emit_objtoreg(f, &p->q1, q1typ(p), zreg);
+ emit_constanttotemp(f,0xffffff80);
+ emit(f,"\tadd\t%s\n",regnames[zreg]);
+ emit(f,"\txor\t%s\n",regnames[zreg]);
+ cleartempobj(f,zreg);
+ save_result(f, p);
+ break;
+ case SHORT:
+ emit_objtoreg(f, &p->q1, q1typ(p), zreg);
+ emit_constanttotemp(f,0xffff8000);
+ emit(f,"\tadd\t%s\n",regnames[zreg]);
+ emit(f,"\txor\t%s\n",regnames[zreg]);
+ cleartempobj(f,zreg);
+ save_result(f, p);
+ break;
+ }
+// settempobj(f,zreg,&p->z,0,0);
+ } else if(sizetab[q1typ(p) & NQ] >= sizetab[ztyp(p) & NQ]) { // Reducing the size, must mask off excess bits...
+ if(DBGMSG)
+ emit(f,"\t\t\t\t\t\t// (convert - reducing type %x to %x\n",q1typ(p),ztyp(p));
+
+ // If Z is not a register then we're storing a halfword or byte, and thus don't need to mask...
+
+ if(((p->q1.flags&(REG|DREFOBJ))==REG) && (p->z.flags&(REG|DREFOBJ))!=REG) {
+ if(p->z.flags&DREFOBJ) { // Can't use stmpdec for dereferenced objects
+ emit_prepobj(f, &p->z, t, zreg, 0); // Need an offset
+ emit_objtoreg(f, &p->q1, q1typ(p), tmp);
+ save_temp(f,p,zreg);
+#if 0
+ emit_prepobj(f, &p->z, t, tmp, 0); // Need an offset
+ emit(f, "\texg\t%s\n", regnames[q1reg]);
+// if(!isstackparam(&p->z) || (p->z.flags&DREFOBJ))
+ emit_sizemod(f,ztyp(p));
+ emit(f, "\tst\t%s\n", regnames[q1reg]);
+ if(p->z.am && p->z.am->disposable && p->q1.am && p->q1.am->disposable)
+ emit(f, "\t\t\t\t\t\t// Both q1 and z are disposable, not bothering to undo exg\n");
+ else
+ emit(f, "\texg\t%s\n", regnames[q1reg]);
+#endif
+ }
+ else {
+ // Use stmpdec if q1 is already in a register...
+ emit_prepobj(f, &p->z, ztyp(p), tmp, 4); // Need an offset
+ if(!isstackparam(&p->z))
+ emit_sizemod(f,ztyp(p));
+ emit(f,"\tstmpdec\t%s\n",regnames[q1reg]);
+ }
+ }
+ else { // Destination is a register - we must mask...
+ // Potential optimisation here - track which ops could have caused a value to require truncation.
+ // Also figure out what's happening next to the value. If it's only being added, anded, ored, xored
+ // and then truncated by a write to memory we don't need to worry.
+ if(!isreg(q1) || !isreg(z) || q1reg!=zreg) // Do we just need to mask in place, or move the value first?
+ {
+ if(!isreg(z))
+ zreg=t1;
+ emit_prepobj(f, &p->z, ztyp(p), t1, 0);
+
+ emit_objtoreg(f, &p->q1, t,tmp);
+ emit(f,"\t\t\t\t\t\t//Saving to reg %s\n",regnames[zreg]);
+ save_temp(f, p, zreg);
+ }
+// else
+ if(zreg!=sp && (p->z.flags&(DREFOBJ|REG))==REG)
+ {
+ switch(ztyp(p)&NQ) {
+ case SHORT:
+ emit_constanttotemp(f, 0xffff);
+ emit(f, "\tand\t%s\n", regnames[zreg]);
+ break;
+ case CHAR:
+ emit_constanttotemp(f, 0xff);
+ emit(f, "\tand\t%s\n", regnames[zreg]);
+ break;
+ default:
+ emit(f,"\t\t\t\t\t\t//No need to mask - same size\n");
+ break;
+ }
+ }
+ }
+ }
+ continue;
+ }
+
+ if (c == KOMPLEMENT) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//comp\n");
+ emit_objtoreg(f, &p->q1, q1typ(p), zreg);
+ emit_constanttotemp(f,-1);
+ emit(f, "\txor\t%s\n", regnames[zreg]);
+// cleartempobj(f,zreg);
+ save_result(f, p);
+ continue;
+ }
+ // May not need to actually load the register here - certainly check before emitting code.
+ if (c == SETRETURN) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//setreturn\n");
+ emit_objtoreg(f, &p->q1, q1typ(p), zreg);
+ BSET(regs_modified, p->z.reg);
+ continue;
+ }
+ // Investigate - May not be needed for register mode?
+ if (c == GETRETURN) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// (getreturn)");
+ if (p->q1.reg) {
+ zreg = p->q1.reg;
+ save_result(f, p);
+ } else {
+ if(DBGMSG)
+ emit(f, " not reg\n");
+ p->z.flags = 0;
+ }
+ continue;
+ }
+ // OK - figure out what the bvunite stuff is all about.
+ if (c == CALL) {
+ int reg;
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//call\n");
+ if ((p->q1.flags & (VAR | DREFOBJ)) == VAR && p->q1.v->fi && p->q1.v->fi->inline_asm) {
+ emit_inline_asm(f, p->q1.v->fi->inline_asm);
+ cleartempobj(f,t1);
+ cleartempobj(f,tmp);
+ /* FIXME - restore stack from pushed arguments? */
+ } else {
+ /* FIXME - deal with different object types here */
+ if (p->q1.v->storage_class == STATIC) {
+ // FIXME - double-check that we shouldn't include an offset here.
+ emit_pcreltotemp2(f, &p->q1);
+ if (p->q1.flags & DREFOBJ) {
+ emit(f, "\taddt\t%s\t//Deref function pointer\n", regnames[pc]);
+ emit(f, "\tldt\n\texg\t%s\n", regnames[pc]);
+ } else
+ emit(f, "\tadd\t%s\n", regnames[pc]);
+ } else if (p->q1.v->storage_class == EXTERN) {
+ if (p->q1.flags & DREFOBJ) { // Is this a function pointer?
+ emit_externtotemp(f, p->q1.v->identifier, p->q1.val.vmax);
+ emit(f, "\tldt\t// deref function ptr\n");
+ emit(f, "\texg\t%s\n", regnames[pc]);
+ }
+ else {
+ emit_pcreltotemp2(f, &p->q1);
+ emit(f, "\tadd\t%s\n", regnames[pc]);
+ }
+ } else {
+ emit_objtoreg(f, &p->q1, t, tmp);
+ emit(f, "\texg\t%s\n", regnames[pc]);
+ }
+
+ cleartempobj(f,tmp);
+
+ /* If we have an addressingmode, see if we're able to defer stack popping. */
+ if(p->z.am)
+ {
+ switch(p->z.am->deferredpop)
+ {
+ /* If we couldn't defer popping due to flow control changes, we need to pop any previously
+ deferred stack entries at this point.*/
+ case DEFERREDPOP_FLOWCONTROL:
+ emit(f,"\t\t\t\t\t\t// Flow control - popping %d + %d bytes\n",pushedargsize(p),notyetpopped);
+ if(pushedargsize(p)+notyetpopped)
+ {
+ emit_constanttotemp(f, pushedargsize(p)+notyetpopped);
+ emit(f, "\tadd\t%s\n", regnames[sp]);
+ }
+ pushed -= pushedargsize(p);
+ notyetpopped=0;
+ break;
+
+ /* If we couldn't defer popping due to nested calls then we only pop this function's stack entries. */
+ case DEFERREDPOP_NESTEDCALLS:
+ emit(f,"\t\t\t\t\t\t// Nested call - popping %d bytes\n",pushedargsize(p));
+ if(pushedargsize(p))
+ {
+ emit_constanttotemp(f, pushedargsize(p));
+ emit(f, "\tadd\t%s\n", regnames[sp]);
+ }
+ pushed -= pushedargsize(p);
+ break;
+
+ /* Otherwise, we're OK to defer popping until later. */
+ case DEFERREDPOP_OK:
+ notyetpopped+=pushedargsize(p);
+ pushed -= pushedargsize(p);
+ emit(f,"\t\t\t\t\t\t// Deferred popping of %d bytes (%d in total)\n",pushedargsize(p),notyetpopped);
+ break;
+ }
+ }
+ else if(pushedargsize(p))
+ {
+ emit_constanttotemp(f, pushedargsize(p));
+ pushed -= pushedargsize(p);
+ emit(f, "\tadd\t%s\n", regnames[sp]);
+ }
+// cleartempobj(f,tmp);
+ cleartempobj(f,t1);
+ }
+ /*FIXME*/
+ if ((p->q1.flags & (VAR | DREFOBJ)) == VAR && p->q1.v->fi
+ && (p->q1.v->fi->flags & ALL_REGS)) {
+ bvunite(regs_modified, p->q1.v->fi->regs_modified, RSIZE);
+ } else {
+ int i;
+ for (i = 1; i <= MAXR; i++) {
+ if (regscratch[i])
+ BSET(regs_modified, i);
+ }
+ }
+ continue;
+ }
+
+ if ((c == ASSIGN || c == PUSH) && t == 0) {
+ printf("Bad type for assign / push\n");
+ ierror(0);
+ }
+ // Basically OK.
+ if (c == PUSH) {
+ int matchreg;
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// (a/p push)\n");
+
+ /* Handle composite types */
+ if((t & NQ) > POINTER || ((t & NQ) == CHAR && zm2l(p->q2.val.vmax) != 1)) {
+// if(DBGMSG)
+ emit(f,"\t\t\t\t\t\t// Pushing composite type - size %d, pushed size %d\n",opsize(p),pushsize(p));
+ emit_inlinepush(f,p,t);
+ pushed += pushsize(p);
+ }
+ else
+ {
+ /* need to take dt into account */
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// a: pushed %ld, regnames[sp] %s\n", pushed, regnames[sp]);
+ switch(t&NQ)
+ {
+ case INT:
+ case LONG:
+ case POINTER:
+ emit_objtoreg(f, &p->q1, t, tmp);
+ emit(f, "\tstdec\t%s\n", regnames[sp]);
+ break;
+ default:
+ printf("Pushing unhandled type 0x%x to the stack\n",t);
+ ierror(0);
+ break;
+ }
+ pushed += pushsize(p);
+ }
+ continue;
+ }
+
+ if (c == ASSIGN) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// (a/p assign)\n");
+ if (((t & NQ) == STRUCT) || ((t & NQ) == UNION) || ((t & NQ) == ARRAY)
+ || ((t & NQ) == CHAR && opsize(p) != 1)) {
+ emit_inlinememcpy(f,p,t);
+ } else {
+ // Is the small speedup here worth the complexity? (Yes, because it improves code density)
+ // Use stmpdec if q1 is already in a register and we're not using addressing modes...
+ if(!check_am(p) && ((p->q1.flags&(REG|DREFOBJ))==REG) && !(p->z.flags®))
+ {
+ if(p->z.flags&DREFOBJ) // Can't use stmpdec for dereferenced objects
+ {
+ emit_prepobj(f, &p->z, t, tmp, 0);
+ emit(f, "\texg\t%s\n", regnames[q1reg]);
+ emit_sizemod(f,t);
+ emit(f, "\tst\t%s\n", regnames[q1reg]);
+ if(p->z.am && p->z.am->disposable)
+ {
+ cleartempobj(f,tmp);
+ emit(f, "\t\t\t\t\t\t// Object is disposable, not bothering to undo exg\n");
+ }
+ else
+ emit(f, "\texg\t%s\n", regnames[q1reg]);
+ }
+ else
+ {
+ emit_prepobj(f, &p->z, t, tmp, 4); // Need an offset
+ if(!isstackparam(&p->z))
+ emit_sizemod(f,t);
+ emit(f,"\tstmpdec\t%s\n",regnames[q1reg]);
+ cleartempobj(f,tmp);
+ }
+ }
+ else
+ {
+ emit_prepobj(f, &p->z, t, t1, 0);
+ emit_objtoreg(f, &p->q1, t, tmp);
+ save_temp(f, p, t1);
+ }
+ }
+ continue;
+ }
+ // Seems to work.
+ if (c == ADDRESS) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// (address)\n");
+ if(involvesreg(z))
+ {
+ emit_prepobj(f, &p->q1, POINTER, tmp, 0);
+ save_temp(f,p,zreg);
+ }
+ else
+ {
+ emit_prepobj(f, &p->q1, POINTER, zreg, 0);
+ save_result(f, p);
+ }
+ continue;
+ }
+ // OK
+ if (c == MINUS) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// (minus)\n");
+ emit_objtoreg(f, &p->q1, q1typ(p), zreg);
+ emit_constanttotemp(f,0);
+ emit(f, "\texg %s\n\tsub %s\n", regnames[zreg], regnames[zreg]);
+ settempobj(f,tmp,&p->q1,0,0); // Temp contains un-negated value
+ // cleartempobj(f,tmp);
+ save_result(f, p);
+ continue;
+ }
+ // Compare - #
+ // Revisit
+ if (c == TEST) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// (test)\n");
+ if(!emit_objtoreg(f, &p->q1, t, tmp)) /* emit_objtoreg might already have set the Z flag */
+ {
+ emit(f,"\t\t\t\t// flags %x\n",p->q1.flags);
+ if ((p->q1.flags & (REG|DREFOBJ)) == REG) // Can avoid mr if the value came from a register
+ emit(f, "\tand\t%s\n", regnames[p->q1.reg]);
+ else
+ {
+ emit(f, "\tmr\t%s\n\tand\t%s\n", regnames[t1], regnames[t1]);
+ settempobj(f,t1,&p->q1,0,0);
+ }
+// cleartempobj(f,tmp);
+// cleartempobj(f,t1);
+ }
+ continue;
+ }
+ // Compare
+ // Revisit
+ if (c == COMPARE) {
+ if(DBGMSG)
+ {
+ emit(f, "\t\t\t\t\t\t// (compare)");
+ if (q1typ(p) & UNSIGNED)
+ emit(f, " (q1 unsigned)");
+ else
+ emit(f, " (q1 signed)");
+ if (q2typ(p) & UNSIGNED)
+ emit(f, " (q2 unsigned)");
+ else
+ emit(f, " (q2 signed)");
+ emit(f,"\n");
+ }
+
+ // If q2 is a register but q1 isn't we could reverse the comparison, but would then have to reverse
+ // the subsequent conditional branch.
+ // FIXME - can also reverse if one value is cached
+
+ if (!isreg(q1)) {
+ if(isreg(q2)) { // Reverse the test.
+ emit_objtoreg(f, &p->q1, t,tmp);
+ q1reg=q2reg;
+ reversecmp=1;
+ } else { // Neither object is in a register, so load q1 into t1 and q2 into tmp.
+ emit_objtoreg(f, &p->q1, t,t1);
+ cleartempobj(f,t1);
+ q1reg = t1;
+ emit_objtoreg(f, &p->q2, t,tmp);
+ }
+ }
+ else
+ emit_objtoreg(f, &p->q2, t,tmp);
+ if ((!(q1typ(p) & UNSIGNED)) && (!(q2typ(p) & UNSIGNED))) { // If we have a mismatch of signedness we treat as unsigned.
+ int nextop=p->next->code; // Does the sign matter for the branch being done?
+ if(nextop==FREEREG)
+ nextop=p->next->next->code;
+ if((nextop!=BEQ) && (nextop!=BNE))
+ emit(f, "\tsgn\n"); // Signed comparison
+ }
+ emit(f, "\tcmp\t%s\n", regnames[q1reg]);
+ continue;
+ }
+
+ // Division and modulo
+ if ((c == MOD) || (c == DIV)) {
+ int targetreg=zreg;
+ int doneq2=0;
+ // FIXME - do we need to use switch_IC here?
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//Call division routine\n");
+
+ // determine here whether R1 and R2 really need saving - may not be in use, or may be the target register.
+ if(regs[t2] && zreg!=t2)
+ {
+ emit(f, "\tmt\t%s\n\tstdec\t%s\n", regnames[t2], regnames[sp]);
+ cleartempobj(f,tmp);
+ pushed+=4;
+ }
+ if(regs[t2+1] && zreg!=(t2+1))
+ {
+ emit(f, "\tmt\t%s\n\tstdec\t%s\n", regnames[t2 + 1], regnames[sp]);
+ cleartempobj(f,tmp);
+ pushed += 4;
+ }
+ // q1 must be written to t2, q2 must be written to t2+2
+ // if q2 starts in t2 we have to avoid overwriting it.
+
+ // If q1 is already in t2, q2 can't be, so we don't need to worry about swapping
+ if(!isreg(q1) || q1reg!=t2)
+ {
+ emit_objtoreg(f, &p->q1, t,tmp);
+
+ // Need to make sure we're not about to overwrite the other operand!
+ if(isreg(q2) && q2reg==t2)
+ {
+ emit(f,"\texg\t%s\n",regnames[t2]);
+ emit(f,"\tmr\t%s\n",regnames[t2+1]);
+ doneq2=1;
+ }
+ else
+ emit(f, "\tmr\t%s\n", regnames[t2]);
+ }
+ if(!doneq2 && (!isreg(q2) || q2reg!=t2+1))
+ {
+ emit_objtoreg(f, &p->q2, t,tmp);
+ emit(f, "\tmr\t%s\n", regnames[t2 + 1]);
+ }
+ cleartempobj(f,t1);
+ cleartempobj(f,t2);
+
+ if ((!(q1typ(p) & UNSIGNED)) && (!(q2typ(p) & UNSIGNED))) // If we have a mismatch of signedness we treat as unsigned.
+ emit(f, "\t.lipcrel\t_div_s32bys32\n");
+ else
+ emit(f, "\t.lipcrel\t_div_u32byu32\n");
+ emit(f, "\tadd\t%s\n", regnames[pc]);
+
+ // If the next IC is SetReturn from the same register we can skip saving the result.
+ if(next_setreturn(p,zreg))
+ {
+ emit(f,"\t\t\t\t\t\t// Skipping save_result...\n");
+ targetreg=t1;
+ }
+
+ if (c == MOD)
+ {
+ if(targetreg!=t2)
+ emit(f, "\tmt\t%s\n\tmr\t%s\n", regnames[t2], regnames[zreg]);
+ }
+ else
+ {
+ if(targetreg!=t1)
+ emit(f, "\tmt\t%s\n\tmr\t%s\n", regnames[t1], regnames[zreg]);
+ }
+
+ if(regs[t2+1] && zreg!=(t2+1))
+ {
+ emit(f, "\tldinc\t%s\n\tmr\t%s\n", regnames[sp], regnames[t2+1]);
+ pushed -= 4;
+ }
+ if(regs[t2] && zreg!=t2)
+ {
+ emit(f, "\tldinc\t%s\n\tmr\t%s\n", regnames[sp], regnames[t2]);
+ pushed -= 4;
+ }
+
+ cleartempobj(f,tmp);
+ cleartempobj(f,t1);
+
+ // Target not guaranteed to be a register.
+ save_result(f, p);
+
+ continue;
+ }
+
+ // Remaining arithmetic and bitwise operations
+
+ if ((c >= OR && c <= AND) || (c >= LSHIFT && c <= MULT)) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// (bitwise/arithmetic) ");
+ if(DBGMSG)
+ emit(f, "\t//ops: %d, %d, %d\n", q1reg, q2reg, zreg);
+ if(p->q1.am && p->q1.am->type==AM_ADDT)
+ {
+ if(DBGMSG)
+ emit(f,"\t\t\t\t\t\t//Special case - addt\n");
+ // FIXME - if q2 is already in tmp could reverse this
+ if(p->q2.flags&KONST)
+ {
+ zreg=t1;
+ emit_prepobj(f, &p->z, t, t1, 0);
+
+ emit_objtoreg(f, &p->q2, t,tmp);
+ emit(f,"\taddt\t%s\n",regnames[p->q1.reg]);
+ settempobj(f,tmp,&p->z,0,0);
+ save_temp(f, p, zreg);
+ obsoletetempobj(f,t1,&p->z,0);
+// emit(f,"\tmr\t%s\n",regnames[p->z.reg]);
+ }
+ else
+ {
+ zreg=t1;
+ emit_prepobj(f, &p->z, t, t1, 0);
+
+ emit_objtoreg(f, &p->q1, t,tmp);
+ emit(f,"\taddt\t%s\n",regnames[p->q2.reg]);
+ settempobj(f,tmp,&p->z,0,0);
+ save_temp(f, p, zreg);
+ obsoletetempobj(f,t1,&p->z,0);
+// emit(f,"\tmr\t%s\n",regnames[p->z.reg]);
+ }
+ continue;
+ }
+
+ if (involvesreg(q2) && q2reg == zreg) {
+// printf("Target register and q2 are the same! Attempting a switch...\n");
+ if (switch_IC(p)) {
+ preload(f,p,1); // refresh q1reg, etc after switching the IC
+ } else {
+ emit(f,
+ "\t\t\t\t\t\t// WARNING - evading q2 and target collision - check code for correctness.\n");
+ zreg = t1;
+ }
+ }
+ if (involvesreg(q1) && q1reg == zreg)
+ emit(f,"\t\t\t\t\t\t// WARNING - q1 and target collision - check code for correctness.\n");
+
+ if (!isreg(q1) || q1reg != zreg) {
+ emit_objtoreg(f, &p->q1, t,zreg);
+// emit(f, "\tmr\t%s\n", regnames[zreg]); // FIXME - what happens if zreg and q1/2 are the same?
+ }
+ emit_objtoreg(f, &p->q2, t,tmp);
+ if (c >= OR && c <= AND)
+ emit(f, "\t%s\t%s\n", logicals[c - OR], regnames[zreg]);
+ else {
+ if (c == RSHIFT || c==MULT) // Modify right shift operations with appropriate signedness...
+ {
+// printf("q1typ: %x, q2typ: %x, ztyp: %x\n",q1typ(p),q2typ(p),ztyp(p));
+ if (!(t & UNSIGNED))
+ {
+ // Evaluate q1 - if we're dealing with a constant that doesn't have bit 31 set we don't need sgn...
+ if((!(p->typf2 & UNSIGNED) && c==RSHIFT)
+ || (p->q1.flags&(KONST|DREFOBJ)!=KONST)
+ || (val2zmax(&p->q1,p->typf)&0x80000000))
+ emit(f, "\tsgn\n");
+ }
+ }
+ emit(f, "\t%s\t%s\n", arithmetics[c - LSHIFT], regnames[zreg]);
+ if(c==MULT)
+ cleartempobj(f,tmp);
+ }
+ settempobj(f,zreg,&p->z,0,0);
+ cleartempobj(f,zreg);
+ save_result(f, p);
+ continue;
+ }
+ printf("Unhandled IC\n");
+ pric2(stdout, p);
+ ierror(0);
+ }
+ if(function_bottom(f, v, localsize+notyetpopped,firsttail))
+ firsttail=0;
+}
+
+int shortcut(int code, int typ)
+{
+ // Only RSHIFT and AND are safe on 832.
+ // So far have seen shortcut requests for
+ // DIV
+ // ADD
+ // RSHIFT
+ // COMPARE
+ // SUB
+ // LSHIFT
+ // AND
+ // MULT
+ // OR
+
+// printf("Evaluating shortcut for code %d, type %x\n",code,typ);
+ if(code==RSHIFT)
+ return(1);
+ if(code==AND)
+ return(1);
+
+ return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t, int vararg, struct Typ *d)
+{
+ int f;
+ f = t->flags & NQ;
+ if(is_varargs(d)) /* Disallow register parameters for varargs functions */
+ return(0);
+
+ if (f <= LONG || f == POINTER) {
+ if (m->gregs >= REGPARM_COUNT)
+ return 0;
+ else
+ return FIRST_GPR + 1 + m->gregs++;
+ }
+ if (ISFLOAT(f)) {
+ return(0);
+/* if (m->fregs >= 0)
+ return 0;
+ else
+ return FIRST_FPR + 2 + m->fregs++;
+*/
+ }
+ return 0;
+}
+
+int iscomment(char *str)
+{
+ char c;
+ while(c=*str++)
+ {
+ if(!c || c=='\n' || c=='/')
+ return(1);
+ if(c!=' '&&c!='\t')
+ return(0);
+ }
+ return(1);
+}
+
+
+int emit_peephole(void)
+{
+ int i;
+ int havemr=0;
+ int havemt=0;
+ int havestore=0;
+ int haveload=0;
+ int loadidx=0;
+ i=emit_f;
+
+ while(i!=emit_l)
+ {
+ int reg,reg2;
+ if(sscanf(emit_buffer[i],"\tmr\tr%d",®)==1)
+ {
+ if(havemt && reg==reg2)
+ {
+ strcpy(emit_buffer[i],"\t//mr\n");
+ return(1);
+ }
+ reg2=reg;
+ havemr=1;
+ havemt=0;
+ }
+ else if(sscanf(emit_buffer[i],"\tmt\tr%d",®)==1)
+ {
+ if(havemr && reg==reg2)
+ {
+ strcpy(emit_buffer[i],"\t//mt\n");
+ return(1);
+ }
+ reg2=reg;
+ havemr=0;
+ havemt=1;
+ }
+ else if(sscanf(emit_buffer[i],"\tst\tr%d",®)==1)
+ {
+ havemr=havemt=0;
+ havestore=1;
+ }
+ else if(sscanf(emit_buffer[i],"\tld\tr%d",®2)==1 && havestore)
+ {
+ havemr=havemt=0;
+ if(reg==reg2 && reg==6) /* Only stack ops - others would be risky due to potential hardware registers. */
+ {
+ loadidx=i;
+ haveload=1;
+// printf("Found matching load directive, r%d\n",reg);
+// strcpy(emit_buffer[i],"\t//nop\n");
+// return(1);
+ }
+ }
+ else if(!iscomment(emit_buffer[i])) /* Check that the next instruction isn't "cond" */
+ {
+ havemr=havemt=0;
+ if(haveload && strncmp(emit_buffer[i],"\tcond",5)) /* If not, we're OK to zero out the load */
+ {
+ strcpy(emit_buffer[loadidx],"\t//nop\n");
+ return(1);
+ }
+ else
+ {
+ havestore=haveload=0;
+ }
+ }
+ i=(i+1)%EMIT_BUF_DEPTH;
+ }
+ return 0;
+}
+
+
+int handle_pragma(const char *s)
+{
+ return(0);
+}
+
+void cleanup_cg(FILE * f)
+{
+}
+
+void cleanup_db(FILE * f)
+{
+ if (f)
+ section = -1;
+}
diff --git a/machines/832/machine.dt b/machines/832/machine.dt
new file mode 100644
index 0000000..526c8d4
--- /dev/null
+++ b/machines/832/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/832/machine.h b/machines/832/machine.h
new file mode 100644
index 0000000..43aba53
--- /dev/null
+++ b/machines/832/machine.h
@@ -0,0 +1,148 @@
+/* EightThirtyTwo backend for vbcc.
+ Based on the "generic" backend.
+*/
+
+/* build-time configurable options: */
+#define NUM_GPRS 9
+#define SCRATCH_GPRS 2
+#define NUM_FPRS 0
+#define NUM_CCRS 0
+#define FIXED_SP 0
+
+#include "dt.h"
+
+/* Define this if you need to build with 0.9g */
+/* #define V09G */
+
+/* internally used by the backend */
+#define FIRST_GPR 1
+#define LAST_GPR (FIRST_GPR+NUM_GPRS-1)
+#define FIRST_FPR (LAST_GPR+1)
+#define LAST_FPR (FIRST_FPR+NUM_FPRS-1)
+#define RESERVED_GPRS 1
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Currently possible are (const,gpr) and (gpr,gpr) */
+/* FIXME - we can make use of ldidx here */
+enum AddressingMode_Type { AM_POSTINC=1, AM_PREDEC, AM_ADDT };
+struct AddressingMode{
+ enum AddressingMode_Type type;
+ int disposable;
+ int deferredpop;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR NUM_GPRS+NUM_FPRS+NUM_CCRS
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 3
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P INT
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+
+extern char flag_832_bigendian;
+#define BIGENDIAN (flag_832_bigendian)
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN (!flag_832_bigendian)
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 1
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+/* Parameters are sometimes passed in registers without __reg. */
+#define HAVE_REGPARMS 1
+#define REGPARM_COUNT 1
+
+/* Parameters on the stack should be pushed in order rather than */
+/* in reverse order. */
+// #define ORDERED_PUSH 1
+// FIXED_SP
+
+/* Structure for reg_parm(). */
+struct reg_handle{
+ unsigned long gregs;
+ unsigned long fregs;
+};
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have implemented our own cost-functions to adapt
+ register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 5
+#define cost_save_reg(x,y) 5
+#define cost_pushpop_reg(x) 1
+
+/* size of buffer for asm-output, this can be used to do
+ peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 16
+
+/* We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+ optimizations on code which can already be implemented by efficient
+ assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+ etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we use unsigned int as size_t (but unsigned long, the default) */
+#define HAVE_INT_SIZET 1
+
+/* we do not need register-pairs */
+#undef HAVE_REGPAIRS
+
+/* We (will eventually) use libcalls for 64-bit and float support */
+/* Enabling this completely changes code generation - investigate. */
+#define HAVE_LIBCALLS 0
+
+/* do not create CONVERT ICs from integers smaller than int to floats */
+#define MIN_INT_TO_FLOAT_TYPE INT
+
+/* do not create CONVERT ICs from floats to ints smaller than int */
+#define MIN_FLOAT_TO_INT_TYPE INT
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 1
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 1
diff --git a/machines/832/tempregs.c b/machines/832/tempregs.c
new file mode 100644
index 0000000..c4b177f
--- /dev/null
+++ b/machines/832/tempregs.c
@@ -0,0 +1,624 @@
+/*
+To do:
+ Peephole optimise away such constructs as mr r0, mt r0
+ | Optimise addresses of stack variables - lea's can mostly be replaced with simple adds.
+ Detect absolute moves to reg, prune any that aren't needed.
+
+ tempreg logic should be correct - now it's up to machine.c to make good use of it.
+*/
+
+zmax val2zmax(struct obj *o, int t)
+{
+ union atyps *p = &o->val;
+ t &= NU;
+ if (t == CHAR)
+ return (zc2zm(p->vchar));
+ if (t == (UNSIGNED | CHAR))
+ return (zuc2zum(p->vuchar));
+ if (t == SHORT)
+ return (zs2zm(p->vshort));
+ if (t == (UNSIGNED | SHORT))
+ return (zus2zum(p->vushort));
+
+ /*
+ if(t==FLOAT) return(zf2zld(p->vfloat);emitzld(f,vldouble);}
+ if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+ if(t==LDOUBLE){emitzld(f,p->vldouble);}
+ */
+
+ if (t == INT)
+ return (zi2zm(p->vint));
+ if (t == (UNSIGNED | INT))
+ return (zui2zum(p->vuint));
+ if (t == LONG)
+ return (zl2zm(p->vlong));
+ if (t == (UNSIGNED | LONG))
+ return (zul2zum(p->vulong));
+ if (t == LLONG)
+ return (zll2zm(p->vllong));
+ if (t == (UNSIGNED | LLONG))
+ return (zull2zum(p->vullong));
+ if (t == MAXINT)
+ return (p->vmax);
+ if (t == (UNSIGNED | MAXINT))
+ return (p->vumax);
+ if (t == POINTER)
+ return (zul2zum(p->vulong));
+ printf("#FIXME - no float support yet\n");
+ ierror(0);
+}
+
+static void emit_sizemod(FILE * f, int type)
+{
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//sizemod based on type 0x%x\n", type);
+ switch (type & NQ) {
+ case 0:
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//sizemod type is zero (movefromreg?)");
+ break;
+ case CHAR:
+ emit(f, "\tbyt\n");
+ break;
+ case SHORT:
+ emit(f, "\thlf\n");
+ break;
+ case INT:
+ case LONG:
+ case LLONG:
+ case POINTER:
+ case FUNKT: // Function pointers are dereferenced by calling them.
+ case STRUCT:
+ case UNION:
+ case ARRAY:
+ break; // Structs and unions have to remain as pointers
+ default:
+ printf("emit_sizemod - type %d not handled\n", type);
+ ierror(0);
+ break;
+ }
+}
+
+
+// WARNING: Must invalidate tmp if control flow doesn't change immediately after this instruction.
+
+static void emit_pcreltotemp(FILE * f, char *lab, int suffix)
+{
+ int i;
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//pcreltotemp\n");
+ emit(f, "\t.lipcrel\t%s%d\n", lab, suffix);
+// cleartempobj(f,tmp);
+}
+
+static void emit_pcreltotemp2(FILE *f,struct obj *p)
+{
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//pcreltotemp\n");
+ if (p->v->storage_class == STATIC)
+ emit(f,"\t.lipcrel\t%s%d\n",labprefix, zm2l(p->v->offset));
+ else if(p->v->storage_class == EXTERN)
+ {
+ if(p->val.vmax)
+ emit(f,"\t.lipcrel\t_%s%d\n",p->v->identifier, p->val.vmax);
+ else
+ emit(f,"\t.lipcrel\t_%s\n",p->v->identifier);
+ }
+// cleartempobj(f,tmp);
+}
+
+// tempobj logic should be correct.
+
+static void emit_externtotemp(FILE * f, char *lab, int offset) // FIXME - need to find a way to do this PC-relative.
+{
+#if 0
+ emit(f, "\tldinc\t%s\n", regnames[pc]);
+ if (offset)
+ emit(f, "\t.ref\t_%s, %d\n",lab, offset);
+ else
+ emit(f, "\t.ref\t_%s\n",lab);
+#else
+ if(g_flags[FLAG_PIC]&USEDFLAG)
+ {
+ if (offset)
+ emit(f, "\t.lipcrel\t_%s, %d\n",lab, offset);
+ else
+ emit(f, "\t.lipcrel\t_%s\n",lab);
+ emit(f, "\taddt\t%s\n",regnames[pc]);
+ }
+ else
+ {
+ if (offset)
+ emit(f, "\t.liabs\t_%s, %d\n",lab, offset);
+ else
+ emit(f, "\t.liabs\t_%s\n",lab);
+ }
+#endif
+ cleartempobj(f,tmp);
+}
+
+
+// tempobj logic should be correct.
+
+static void emit_statictotemp(FILE * f, char *lab, int suffix, int offset) // FIXME - need to find a way to do this PC relative
+{
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//statictotemp (FIXME - make PC-relative?)\n");
+ if(g_flags[FLAG_PIC]&USEDFLAG)
+ {
+ emit(f, "\t.lipcrel\t%s%d,%d\n", lab, suffix, offset);
+ emit(f, "\taddt\t%s\n",regnames[pc]);
+ }
+ else
+ {
+ emit(f, "\t.liabs\t%s%d,%d\n", lab, suffix, offset);
+ }
+ cleartempobj(f,tmp);
+}
+
+static int count_constantchunks(zmax v)
+{
+ int chunk = 1;
+ int v2 = (int)v;
+ while (((v2 & 0xffffffe0) != 0) && ((v2 & 0xffffffe0) != 0xffffffe0)) // Are we looking at a sign-extended 6-bit value yet?
+ {
+// printf("%08x\n",v2);
+ v2 >>= 6;
+ ++chunk;
+ }
+ return (chunk);
+}
+
+
+// tempobj logic should be correct.
+
+static void emit_constanttoreg(FILE * f, zmax v,int reg)
+{
+ int matchreg=matchtempkonst(f,v,reg);
+// emit(f,"// matchreg %s\n",regnames[matchreg]);
+
+// if(matchreg==tmp)
+// return;
+// else if(matchreg)
+// emit(f,"\tmt\t%s\n",regnames[matchreg]);
+ if(matchreg) {
+ // Need to deal with the case where a constant is in r0 but required in tmp or vice versa.
+ if(matchreg!=reg) {
+ if(reg==tmp)
+ emit(f,"\tmt\t%s\n",regnames[matchreg]);
+ else
+ emit(f,"\tmr\t%s\n",regnames[reg]);
+ settempkonst(f,reg,v);
+ }
+ } else {
+ emit(f, "\t.liconst\t%d\n", v);
+ settempkonst(f,tmp,v);
+ if(reg!=tmp)
+ {
+ emit(f,"\tmr\t%s\n",regnames[reg]);
+ settempkonst(f,reg,v);
+ }
+ }
+}
+
+static void emit_constanttotemp(FILE * f, zmax v)
+{
+ emit_constanttoreg(f,v,tmp);
+}
+
+
+// tempobj logic should be correct.
+
+static void emit_stackvartotemp(FILE * f, zmax offset, int deref)
+{
+ if (deref) {
+ if (offset) {
+ emit_constanttotemp(f, offset);
+ emit(f, "\tldidx\t%s\n", regnames[sp]);
+ } else
+ emit(f, "\tld\t%s\n", regnames[sp]);
+ } else {
+ if (offset) {
+ emit_constanttotemp(f, offset);
+ emit(f, "\taddt\t%s\n", regnames[sp]);
+ } else
+ emit(f, "\tmt\t%s\n", regnames[sp]);
+ }
+ cleartempobj(f,tmp);
+}
+
+
+// Load the address of a target obj into reg in preparation for a store.
+// If the target is simply a register then does nothing.
+// The nominated register can be tmp or any gpr.
+// Guaranteed not to modify t1 or t2 except when nominated.
+// tempobj logic should be correct.
+
+static void emit_prepobj(FILE * f, struct obj *p, int t, int reg, int offset)
+{
+ int matchreg=0;
+
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// (prepobj %s)\n ", regnames[reg]);
+
+ if (p->flags & REG) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// reg %s - no need to prep\n", regnames[p->reg]);
+ if(p->flags & DREFOBJ)
+ {
+ if (reg == tmp)
+ {
+ emit(f, "\tmt\t%s\n", regnames[p->reg]);
+ cleartempobj(f,tmp);
+ }
+ }
+ return;
+ }
+
+ if(!offset)
+ matchreg=matchtempobj(f,p,1,t1); // FIXME - we're hunting for varadr here.
+
+ if(matchreg)
+ {
+ if(DBGMSG)
+ emit(f,"\n\t\t\t\t\t\t// required value found in %s\n",regnames[matchreg]);
+ if(matchreg==reg)
+ return;
+ else if(matchreg==tmp) {
+ emit(f,"\tmr\t%s\n",regnames[reg]);
+ settempobj(f,reg,p,0,0);
+ return;
+ } else {
+ emit(f,"\tmt\t%s\n",regnames[matchreg]);
+ settempobj(f,tmp,p,0,0);
+ if(reg!=tmp)
+ {
+ emit(f,"\tmr\t%s\n",regnames[reg]);
+ settempobj(f,reg,p,0,0);
+ }
+ return;
+ }
+ }
+
+ if (p->flags & DREFOBJ) {
+ if (p->flags & VARADR)
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//varadr AND ");
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// deref\n");
+ /* Dereferencing a pointer */
+ if (p->flags & KONST) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// const to %s\n",regnames[reg]);
+ emit_constanttoreg(f, val2zmax(p, p->dtyp) + offset,reg);
+// if (reg != tmp)
+// emit(f, "\tmr\t%s\n", regnames[reg]);
+ settempkonst(f,reg,val2zmax(p, p->dtyp) + offset);
+ } else if (p->flags & REG) {
+ if (reg == tmp)
+ {
+ emit(f, "\tmt\t%s\n", regnames[p->reg]);
+ cleartempobj(f,tmp);
+ }
+ else if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// reg %s - no need to prep\n", regnames[p->reg]);
+ } else if (p->flags & VAR) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// var FIXME - deref?\n");
+ if(offset)
+ {
+ printf("emit_prepobj: Offset supplied but object is being dereferenced!\n");
+ ierror(0);
+ }
+ if (isauto(p->v->storage_class)) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// reg - auto\n");
+ emit_stackvartotemp(f, real_offset(p) + offset, 1);
+ if (reg != tmp)
+ {
+ emit(f, "\tmr\t%s\n", regnames[reg]);
+ cleartempobj(f,reg);
+ }
+ } else if (isstatic(p->v->storage_class)) {
+ cleartempobj(f,tmp);
+ cleartempobj(f,reg);
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// static\n");
+ emit(f, "\tldinc\tr7\n\t.ref\t%s%d,%d\n",
+ labprefix, zm2l(p->v->offset), offset + p->val.vmax);
+ emit(f, "\tldt\n");
+ if (reg != tmp)
+ emit(f, "\tmr\t%s\n", regnames[reg]);
+ } else if (isextern(p->v->storage_class)) {
+ emit(f, "\t\t\t\t\t\t//Extern\n");
+ emit_externtotemp(f, p->v->identifier, p->val.vmax);
+ emit(f, "\tldt\n");
+ if (reg != tmp)
+ emit(f, "\tmr\t%s\n", regnames[reg]);
+ } else {
+ if(DBGMSG)
+ printf("// emit_prepobj (deref): - unknown storage class!\n");
+ ierror(0);
+ }
+// if(!zmeqto(l2zm(0L),p->val.vmax)){
+// emit(f," offset ");
+// emit(f," FIXME - deref?\n");
+// emit_constanttotemp(f,val2zmax(f,p,LONG));
+// emit(f,"\tmr\t%s\n",regnames[reg]);
+// emit_pcreltotemp(f,labprefix,zm2l(p->v->offset));
+// emit(f,"\tadd\t%s\n",regnames[reg]);
+// }
+ }
+ } else {
+ if (p->flags & REG) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// reg %s - no need to prep\n", regnames[p->reg]);
+ } else if (p->flags & VAR) {
+ if (isauto(p->v->storage_class)) {
+ /* Set a register to point to a stack-base variable. */
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// var, auto|reg\n");
+ if (p->v->storage_class == REGISTER)
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// (is actually REGISTER)\n");
+ emit_stackvartotemp(f, real_offset(p) + offset, 0);
+ if (reg != tmp)
+ emit(f, "\tmr\t%s\n\n", regnames[reg]);
+ } else if (isextern(p->v->storage_class)) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// extern (offset %d)\n", p->val.vmax);
+ emit_externtotemp(f, p->v->identifier, p->val.vmax + offset);
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// extern pe %s varadr\n", p->flags & VARADR ? "is" : "not");
+ if (reg != tmp)
+ emit(f, "\tmr\t%s\n", regnames[reg]);
+ } else if (isstatic(p->v->storage_class)) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// static\n");
+// emit(f, "\tldinc\tr7\n\t.ref\t%s%d,%d\n",
+// labprefix, zm2l(p->v->offset), offset + p->val.vmax);
+ if(g_flags[FLAG_PIC]&USEDFLAG)
+ {
+ emit(f, "\t.lipcrel\t%s%d,%d\n",
+ labprefix, zm2l(p->v->offset), offset + p->val.vmax);
+ emit(f, "\taddt\t%s\n",regnames[pc]);
+ }
+ else
+ emit(f, "\t.liabs\t%s%d,%d\n",
+ labprefix, zm2l(p->v->offset), offset + p->val.vmax);
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// static pe %s varadr\n", p->flags & VARADR ? "is" : "not");
+ if (reg != tmp)
+ emit(f, "\tmr\t%s\n", regnames[reg]);
+ } else {
+ if(DBGMSG)
+ printf("emit_prepobj: - unknown storage class!\n");
+ ierror(0);
+ }
+ settempobj(f,tmp,p,0,1);
+ settempobj(f,reg,p,0,1);
+ }
+ }
+}
+
+
+// Returns 1 if the Z flag has been set (i.e. a load has occurred)
+// Guaranteed not to modify t1 or t2.
+
+static int emit_objtoreg(FILE * f, struct obj *p, int t,int reg)
+{
+ int result=0;
+ int matchreg;
+ int elementary;
+ int postinc=0;
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// (obj to %s) flags %x type %x\n",regnames[reg],p->flags,t);
+
+ /* If we're dealing with an elementary type on the stack we'll copy the actual object into
+ a register. If we're dealing with a composite type, or taking the address of an elementary
+ type then instead we'll take its address into the register. There's a subtlety to take care
+ of with ASSIGN ICs and inline memcpy/strcpy where they type can be CHAR with a size!=1.
+ I hack around this by overriding type in the parent fucction. */
+ if ((!(p->flags & VARADR)) && ((t & NQ) != STRUCT) && ((t & NQ) != UNION) && ((t & NQ) != ARRAY))
+ elementary=1;
+ else
+ elementary=0;
+
+ matchreg=matchtempobj(f,p,0,reg);
+
+ if ((p->flags & (REG|DREFOBJ)) == REG) {
+ settempobj(f,reg,p,0,0);
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// reg %s - only match against tmp\n", regnames[p->reg]);
+ if (reg == p->reg)
+ return(0);
+ if(matchreg!=tmp)
+ {
+ emit(f,"\tmt\t%s\n",regnames[p->reg]);
+ settempobj(f,tmp,p,0,0);
+ }
+ if(reg!=tmp)
+ {
+ emit(f, "\tmr\t%s\n", regnames[reg]);
+ settempobj(f,reg,p,0,0);
+ }
+ return(0);
+ }
+
+ if(matchreg)
+ {
+ if(DBGMSG)
+ emit(f,"\n\t\t\t// required value found in %s\n",regnames[matchreg]);
+ if(matchreg==reg)
+ return(0);
+ if(matchreg!=tmp)
+ {
+ emit(f,"\tmt\t%s\n",regnames[matchreg]);
+ settempobj(f,tmp,p,0,0);
+ }
+ if(reg!=tmp)
+ {
+ emit(f,"\tmr\t%s\n",regnames[reg]);
+ settempobj(f,reg,p,0,0);
+ }
+ emit(f,"\t\t\t\t//return 0\n");
+ return(0);
+ }
+
+ // FIXME - does this have implications for structs, unions, fptrs, etc?
+ if(p->flags&VARADR)
+ {
+ emit_prepobj(f,p,t,reg,0);
+ return(0);
+ }
+ if ((p->flags & (KONST | DREFOBJ)) == (KONST | DREFOBJ)) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// const/deref\n");
+ matchreg=matchtempkonst(f, val2zmax(p, p->dtyp),tmp);
+ if(matchreg && matchreg!=tmp) {
+ emit_sizemod(f, t);
+ emit(f,"\tld\t%s\n",regnames[matchreg]);
+ } else {
+ emit_prepobj(f, p, t, tmp, 0);
+ emit_sizemod(f, t);
+ emit(f, "\tldt\n");
+ }
+ settempobj(f,tmp,p,0,0);
+ settempobj(f,reg,p,0,0);
+ if(reg!=tmp)
+ emit(f,"\tmr\t%s\n",regnames[reg]);
+ return(1);
+ }
+
+// printf("p->flags %x, type %d\n",p->flags,t);
+
+ if (p->flags & DREFOBJ) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// deref \n");
+ /* Dereferencing a pointer */
+ if (p->flags & REG) {
+ switch (t & NQ) {
+ case CHAR:
+ if (p->am && p->am->type == AM_POSTINC)
+ {
+ emit(f, "\tldbinc\t%s\n", regnames[p->reg]);
+ postinc=1;
+ }
+ else if (p->am && p->am->disposable)
+ emit(f,
+ "\tldbinc\t%s\n//Disposable, postinc doesn't matter.\n", regnames[p->reg]);
+ else
+ emit(f, "\tbyt\n\tld\t%s\n", regnames[p->reg]);
+ break;
+ case SHORT:
+ emit(f, "\thlf\n");
+ emit(f, "\tld\t%s\n", regnames[p->reg]);
+ break;
+ case INT:
+ case LONG:
+ case POINTER:
+ if (p->am && p->am->type == AM_POSTINC)
+ {
+ emit(f, "\tldinc\t%s\n", regnames[p->reg]);
+ postinc=4;
+ }
+ else
+ emit(f, "\tld\t%s\n", regnames[p->reg]);
+ break;
+ case STRUCT:
+ case UNION:
+ case ARRAY:
+ case FUNKT: // Function pointers are dereferenced by calling them.
+ emit(f, "\tmt\t%s\n", regnames[p->reg]);
+ break;
+ default:
+ fprintf(stderr,"Objtoreg - unhandled type %d\n",t);
+ ierror(0);
+ break;
+ }
+ result=1;
+ } else {
+ emit_prepobj(f, p, t, tmp, 0);
+ // Exclusions for fptrs, structs and unions to avoid double-dereference.
+ // Included array type in these exclusions. FIXME - is this sufficient?
+ if ((t & NQ) != FUNKT && (t & NQ) != STRUCT && (t & NQ) != UNION && (t & NQ) != ARRAY)
+ {
+ emit_sizemod(f, t);
+ emit(f, "\tldt\n");
+ result=1;
+ }
+ }
+ } else {
+ if (p->flags & REG) {
+ // Already handled in the preamble.
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// reg %s\n", regnames[p->reg]);
+ emit(f, "\tmt\t%s\n", regnames[p->reg]);
+ } else if (p->flags & VAR) {
+ if (isauto(p->v->storage_class)) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// var, auto|reg\n");
+ /* Do we need to deference? */
+ if (elementary) {
+ if (real_offset(p)) {
+ emit_constanttotemp(f, real_offset(p));
+ if(!isstackparam(p))
+ emit_sizemod(f, t);
+ emit(f, "\tldidx\t%s\n", regnames[sp]);
+ } else {
+ emit_sizemod(f, t);
+ emit(f, "\tld\t%s\n", regnames[sp]);
+ }
+ result=1;
+ } else {
+ if (real_offset(p)) {
+ emit_constanttotemp(f, real_offset(p));
+ emit(f, "\taddt\t%s\n", regnames[sp]);
+ } else {
+ emit(f, "\tmt\t%s\n", regnames[sp]);
+ }
+ }
+ } else if (isextern(p->v->storage_class)) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// extern\n");
+ emit_externtotemp(f, p->v->identifier, p->val.vmax);
+ // Structs, unions and arrays have to remain as pointers
+ if (elementary) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//extern deref\n");
+ emit_sizemod(f, t);
+ emit(f, "\tldt\n");
+ result=1;
+ }
+ } else if (isstatic(p->v->storage_class)) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//static %s\n", p->flags & VARADR ? "varadr" : "not varadr");
+ emit_statictotemp(f, labprefix, zm2l(p->v->offset), p->val.vmax);
+ // Structs, unions and arrays have to remain as pointers
+ if (elementary) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t//static deref\n");
+ emit_sizemod(f, t);
+ emit(f, "\tldt\n");
+ result=1;
+ }
+ } else {
+ printf("Objtotemp: Unhandled storage class: %d\n", p->v->storage_class);
+ ierror(0);
+ }
+ } else if (p->flags & KONST) {
+ if(DBGMSG)
+ emit(f, "\t\t\t\t\t\t// const\n");
+ emit_constanttotemp(f, val2zmax(p, t));
+ } else {
+ printf("Objtotemp: unknown flags %d\n", p->flags);
+ ierror(0);
+ }
+ }
+ if(reg!=tmp)
+ emit(f,"\tmr\t%s\n",regnames[reg]);
+ settempobj(f,reg,p,-postinc,0);
+ settempobj(f,tmp,p,-postinc,0);
+ return(result);
+}
+
diff --git a/machines/alpha/machine.c b/machines/alpha/machine.c
new file mode 100755
index 0000000..c5038c0
--- /dev/null
+++ b/machines/alpha/machine.c
@@ -0,0 +1,1707 @@
+/* Code generator for a DEC Alpha 64bit RISC cpu with 32 */
+/* general purpose and 32 floating point registers. */
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+#include "dwarf2.c"
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for DEC Alpha V0.3c (c) in 1997-2000 by Volker Barthelmann";
+
+/* Commandline-flags the code-generator accepts */
+int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,0,0,0};
+char *g_flags_name[MAXGF]={"cpu","fpu","const-in-data","sd","merge-constants","stabs","no-builtins"};
+union ppi g_flags_val[MAXGF];
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* Tabelle fuer die Groesse der einzelnen Typen */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. */
+char *regnames[MAXR+1]={"noreg",
+ "$0","$1","$2","$3","$4","$5","$6","$7",
+ "$8","$9","$10","$11","$12","$13","$14","$15",
+ "$16","$17","$18","$19","$20","$21","$22","$23",
+ "$24","$25","$26","$27","$28","$29","$30","$31",
+ "$f0","$f1","$f2","$f3","$f4","$f5","$f6","$f7",
+ "$f8","$f9","$f10","$f11","$f12","$f13","$f14","$f15",
+ "$f16","$f17","$f18","$f19","$f20","$f21","$f22","$f23",
+ "$f24","$f25","$f26","$f27","$f28","$f29","$f30","$f31"};
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* A type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1]={0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,
+ 1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+
+struct reg_handle empty_reg_handle={0};
+
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+static long malign[MAX_TYPE+1]= {1,1,2,4,8,8,4,8,8,1,8,1,1,1,4,1};
+static long msizetab[MAX_TYPE+1]={1,1,2,4,8,8,4,8,8,0,8,0,0,0,4,0};
+
+static struct Typ ltyp={LONG};
+
+static char x_t[MAX_TYPE+1]={'?','b','w','l','q','q','s','t','t','?','q'};
+
+static int sp=31; /* Stackpointer */
+static int gp=30; /* Global pointer */
+static int lr=27; /* Link Register */
+static int vp=28; /* Virtual frame pointer */
+static int r31=32; /* Read as zero */
+static int f31=64; /* Read as zero */
+static int sd=14; /* SmallDataPointer */
+static int t1=2,t2=3,t3=4; /* Temporaries used by code generator */
+static int t4=5,t5=6;
+static int f1=34,f2=35,f3=36; /* Temporaries used by code generator */
+
+#define DATA 0
+#define BSS 1
+#define CODE 2
+
+static char *marray[]={"__ALPHA__",0};
+
+static int section=-1,newobj,crsave,helpl,helps,stabs;
+static char *codename="\t.text\n",*dataname="\t.data\n",*bssname="";
+static int balign(struct obj *);
+static char *labprefix="$C",*idprefix="";
+static long framesize,frameoffset;
+static void probj2(FILE *f,struct obj *p,int t);
+
+#define ESGN 1
+#define EUNS 2
+static int st[MAXR+1];
+
+static struct fpconstlist {
+ struct fpconstlist *next;
+ int label,typ;
+ union atyps val;
+} *firstfpc;
+
+static void move_reg(FILE *f,int s,int t)
+{
+ if(t==r31||t==f31) ierror(0);
+ if(s<=32&&t>32) ierror(0);
+ if(t<=32&&s>32) ierror(0);
+ if(s==t) return;
+ if(s<=32){
+ emit(f,"\tbis\t%s,%s,%s\n",regnames[r31],regnames[s],regnames[t]);
+ }else{
+ emit(f,"\tcpys\t%s,%s,%s\n",regnames[s],regnames[s],regnames[t]);
+ }
+ st[t]=st[s];
+}
+
+static int addfpconst(struct obj *o,int t)
+{
+ struct fpconstlist *p=firstfpc;
+ t&=NQ;
+ if(g_flags[4]&USEDFLAG){
+ for(p=firstfpc;p;p=p->next){
+ if(t==p->typ){
+ eval_const(&p->val,t);
+ if(t==INT&&zmeqto(vmax,zi2zm(o->val.vint))) return p->label;
+ if(t==LONG&&zmeqto(vmax,zl2zm(o->val.vlong))) return p->label;
+ if(t==LLONG&&zmeqto(vmax,zll2zm(o->val.vllong))) return p->label;
+ if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+ if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+ if(t==LDOUBLE&&zldeqto(vldouble,o->val.vldouble)) return p->label;
+ }
+ }
+ }
+ p=mymalloc(sizeof(struct fpconstlist));
+ p->next=firstfpc;
+ p->label=++label;
+ p->typ=t;
+ p->val=o->val;
+ firstfpc=p;
+ return p->label;
+}
+
+#define REG_IND 1
+#define IMM_IND 2
+
+static struct obj *cam(int flags,int base,int align,long offset)
+/* Initializes an addressing-mode structure and returns a pointer to */
+/* that object. Will not survive a second call! */
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ am.offset=offset;
+ am.align=align;
+ return &obj;
+}
+
+void title(FILE *f)
+{
+ static int done;
+ extern char *inname; /*grmpf*/
+ if(!done&&f){
+ done=1;
+ emit(f,"\t.file\t\"%s\"\n",inname);
+ }
+}
+
+static char *dct[]={"??","byte","short","long","quad","long","long","quad","??","??","??","??"};
+
+static void load_address(FILE *f,int r,struct obj *o,int typ)
+/* Generates code to load the address of a variable into register r. */
+{
+ if((o->flags&VAR)&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+ long of=zm2l(o->v->offset);
+ if(of>=0)
+ of+=frameoffset+zm2l(o->val.vlong);
+ else
+ of=-of-zm2l(maxalign)+framesize+zm2l(o->val.vmax);
+ if(of>32767) ierror(0);
+ emit(f,"\tlda\t%s,%ld(%s)\n",regnames[r],of,regnames[sp]);
+ }else{
+ emit(f,"\tlda\t%s,",regnames[r]);
+ probj2(f,o,typ);emit(f,"\n");
+ }
+ st[r]=ESGN;
+}
+static void load_obj(FILE *f,int r,struct obj *o,int typ,int tmp)
+{
+ int adr,shift,al;
+ switch(typ&NQ){
+ case POINTER:
+ case LDOUBLE:
+ case DOUBLE:
+ case FLOAT:
+ case LLONG:
+ case LONG:
+ case INT:
+ emit(f,"\tld%c\t%s,",x_t[typ&NQ],regnames[r]);
+ probj2(f,o,typ);emit(f,"\n");
+ st[r]=ESGN;return;
+ case SHORT:
+ al=balign(o);
+ if(al>=0){
+ emit(f,"\tldq_u\t%s,",regnames[r]);
+ probj2(f,o,typ);emit(f,"\n");
+ shift=64-16-al*8;
+ if(shift) emit(f,"\tsll\t%s,%d,%s\n",regnames[r],shift,regnames[r]);
+ if(typ&UNSIGNED){
+ emit(f,"\tsrl\t%s,%d,%s\n",regnames[r],64-16,regnames[r]);
+ st[r]=EUNS;
+ }else{
+ emit(f,"\tsra\t%s,%d,%s\n",regnames[r],64-16,regnames[r]);
+ st[r]=ESGN;
+ }
+ return;
+ }
+ adr=0;
+ if(o->am&&o->am->offset==0)
+ adr=o->am->base;
+ else if(zmeqto(o->val.vmax,l2zm(0L)))
+ adr=o->reg;
+ if(!adr){
+ adr=tmp;load_address(f,adr,o,POINTER);
+ }
+
+ if(typ&UNSIGNED){
+ emit(f,"\tbic\t%s,6,%s\n",regnames[adr],regnames[t4]); /* ldq_u ? */
+ emit(f,"\tldq\t%s,0(%s)\n",regnames[t5],regnames[t4]);
+ emit(f,"\tbic\t%s,1,%s\n",regnames[adr],regnames[t4]);
+ emit(f,"\textwl\t%s,%s,%s\n",regnames[t5],regnames[t4],regnames[r]);
+ /*
+ emit(f,"\tbic\t%s,2,%s\n",regnames[adr],regnames[t4]);
+ emit(f,"\tand\t%s,2,%s\n",regnames[adr],regnames[t5]);
+ emit(f,"\tldq\t%s,0(%s)\n",regnames[r],regnames[t4]);
+ emit(f,"\textwh\t%s,%s,%s\n",regnames[r],regnames[t5],regnames[r]);
+ */
+ st[r]=EUNS;return;
+ }else{
+ emit(f,"\tbic\t%s,6,%s\n",regnames[adr],regnames[t4]);
+ emit(f,"\tand\t%s,6,%s\n",regnames[adr],regnames[t5]);
+ emit(f,"\tldq\t%s,0(%s)\n",regnames[r],regnames[t4]);
+ emit(f,"\tlda\t%s,2(%s)\n",regnames[t5],regnames[t5]);
+ emit(f,"\textqh\t%s,%s,%s\n",regnames[r],regnames[t5],regnames[r]);
+ emit(f,"\tsra\t%s,48,%s\n",regnames[r],regnames[r]);
+ st[r]=ESGN;return;
+ }
+ case CHAR:
+ al=balign(o);
+ if(al>=0){
+ emit(f,"\tldq_u\t%s,",regnames[r]);
+ probj2(f,o,typ);emit(f,"\n");
+ shift=64-8-al*8;
+ if(shift&&al) emit(f,"\tsll\t%s,%d,%s\n",regnames[r],shift,regnames[r]);
+ if(typ&UNSIGNED){
+ if(al==0)
+ emit(f,"\tand\t%s,255,%s\n",regnames[r],regnames[r]);
+ else
+ emit(f,"\tsrl\t%s,%d,%s\n",regnames[r],64-8,regnames[r]);
+ st[r]=EUNS;
+ }else{
+ if(al==0)
+ emit(f,"\tsextb\t%s,%s\n",regnames[r],regnames[r]);
+ else
+ emit(f,"\tsra\t%s,%d,%s\n",regnames[r],64-8,regnames[r]);
+ st[r]=ESGN;
+ }
+ return;
+ }
+ if(typ&UNSIGNED){
+ adr=0;
+ if(o->am&&o->am->offset==0)
+ adr=o->am->base;
+ else if(zmeqto(o->val.vmax,l2zm(0L)))
+ adr=o->reg;
+ if(!adr){
+ adr=tmp; load_address(f,adr,o,POINTER);
+ }
+ emit(f,"\tldq_u\t%s,0(%s)\n",regnames[r],regnames[adr]);
+ emit(f,"\textbl\t%s,%s,%s\n",regnames[r],regnames[adr],regnames[r]);
+ st[r]=EUNS;return;
+ }else{
+ emit(f,"\tldq_u\t%s,",regnames[t5]);
+ probj2(f,o,typ);emit(f,"\n\tlda\t%s,",regnames[t4]);
+ if(o->am) o->am->offset++; else o->val.vmax=zmadd(o->val.vmax,l2zm(1L));
+ probj2(f,o,typ);
+ if(o->am) o->am->offset--; else o->val.vmax=zmsub(o->val.vmax,l2zm(1L));
+ emit(f,"\n\textqh\t%s,%s,%s\n",regnames[t5],regnames[t4],regnames[t5]);
+ emit(f,"\tsra\t%s,56,%s\n",regnames[t5],regnames[r]);
+ st[r]=ESGN;return;
+ }
+ }
+ ierror(0);
+}
+static void load_reg(FILE *f,int r,struct obj *o,int typ,int tmp)
+/* Generates code to load a memory object into register r. tmp is a */
+/* general purpose register which may be used. tmp can be r. */
+{
+ typ&=NU;
+ if(o->am){
+ load_obj(f,r,o,typ,tmp);
+ return;
+ }
+ if(o->flags&KONST){
+ long l;int lab;
+ eval_const(&o->val,typ);
+ if(ISFLOAT(typ)){
+ lab=addfpconst(o,typ);
+ emit(f,"\tlda\t%s,%s%d\n",regnames[tmp],labprefix,lab);
+ emit(f,"\tld%c\t%s,0(%s)\n",x_t[typ&NQ],regnames[r],regnames[tmp]);
+ st[r]=ESGN;
+ return;
+ }
+ if(zmleq(vmax,l2zm(32767))&&zmleq(l2zm(-32768),vmax)){
+ emit(f,"\tlda\t%s,%ld(%s)\n",regnames[r],zm2l(vmax),regnames[r31]);
+ }else{
+/* if((typ&NQ)<INT) ierror(0); */
+ lab=addfpconst(o,typ);
+ emit(f,"\tlda\t%s,%s%d\n",regnames[tmp],labprefix,lab);
+ emit(f,"\tldq\t%s,0(%s)\n",regnames[r],regnames[tmp]);
+ }
+ st[r]=ESGN;
+ return;
+ }
+ if((o->flags&VAR)&&(o->v->storage_class==EXTERN||o->v->storage_class==STATIC)){
+ if(!(o->flags&VARADR)){
+ load_address(f,tmp,o,POINTER);
+ load_obj(f,r,cam(IMM_IND,tmp,balign(o),0L),typ,tmp);
+ }else{
+ load_address(f,r,o,POINTER);
+ }
+ }else{
+ if(o->am||(o->flags&(DREFOBJ|REG))==REG){
+ if(r!=o->reg)
+ move_reg(f,o->reg,r);
+ }else{
+ if(o->flags&DREFOBJ) ierror(0);
+ load_obj(f,r,o,typ,tmp);
+ }
+ }
+}
+
+
+static void store_reg(FILE *f,int r,struct obj *o,int typ)
+/* Generates code to store register r into memory object o. */
+{
+ int adr,t6,t7;
+ if((o->flags&(REG|DREFOBJ))==REG) ierror(0);
+ if(r==t1){ t6=t2;t7=t3;}
+ else if(r==t2) {t6=t1;t7=t3;}
+ else {t6=t1;t7=t2;}
+ if((typ&NQ)>SHORT){
+ if((o->flags&VAR)&&(o->v->storage_class==EXTERN||o->v->storage_class==STATIC)){
+ load_address(f,t6,o,POINTER);
+ emit(f,"\tst%c\t%s,0(%s)\n",x_t[typ&NQ],regnames[r],regnames[t6]);
+ return;
+ }
+ emit(f,"\tst%c\t%s,",x_t[typ&NQ],regnames[r]);
+ probj2(f,o,typ);emit(f,"\n");
+ return;
+ }else{
+ adr=0;
+ if(o->am&&o->am->offset==0){
+ adr=o->am->base;
+ if(adr<1||adr>32) ierror(0);
+ }else if((o->flags®)&&zmeqto(o->val.vmax,l2zm(0L))){
+ adr=o->reg;
+ if(adr<1||adr>32) ierror(0);
+ }
+ if(!adr){
+ adr=t7; load_address(f,adr,o,POINTER);
+ }
+ if(adr<1||adr>32) ierror(0);
+ if((typ&NQ)==SHORT){
+ emit(f,"\tbic\t%s,2,%s\n",regnames[adr],regnames[t4]);
+ emit(f,"\tldl\t%s,0(%s)\n",regnames[t6],regnames[t4]);
+ emit(f,"\tand\t%s,2,%s\n",regnames[adr],regnames[t5]);
+ emit(f,"\tmskwl\t%s,%s,%s\n",regnames[t6],regnames[t5],regnames[t6]);
+ emit(f,"\tinswl\t%s,%s,%s\n",regnames[r],regnames[t5],regnames[t7]);
+ emit(f,"\tbis\t%s,%s,%s\n",regnames[t6],regnames[t7],regnames[t6]);
+ emit(f,"\tstl\t%s,0(%s)\n",regnames[t6],regnames[t4]);
+ return;
+ }else{
+ emit(f,"\tldq_u\t%s,0(%s)\n",regnames[t4],regnames[adr]);
+ emit(f,"\tmskbl\t%s,%s,%s\n",regnames[t4],regnames[adr],regnames[t4]);
+ emit(f,"\tinsbl\t%s,%s,%s\n",regnames[r],regnames[adr],regnames[t5]);
+ emit(f,"\tbis\t%s,%s,%s\n",regnames[t4],regnames[t5],regnames[t4]);
+ emit(f,"\tstq_u\t%s,0(%s)\n",regnames[t4],regnames[adr]);
+ return;
+ }
+ }
+}
+
+static void extend(FILE *f,int r)
+{
+ if(!r) return;
+ if(st[r]==ESGN) return;
+ emit(f,"\taddl\t%s,%s,%s\n",regnames[r],regnames[r31],regnames[r]);
+ st[r]=ESGN;
+}
+static void uextend(FILE *f,int r)
+{
+ if(!r) return;
+ if(st[r]==EUNS) return;
+ emit(f,"\tzapnot\t%s,15,%s\n",regnames[r],regnames[r]);
+ st[r]=EUNS;
+}
+
+static struct IC *do_refs(FILE *,struct IC *);
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long,long);
+static void function_bottom(FILE *f,struct Var *,long,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"bis","xor","and"};
+static char *arithmetics[]={"sll","srl","add","sub","mul","div","rem"};
+
+static struct IC *do_refs(FILE *f,struct IC *p)
+/* Does some pre-processing like fetching operands from memory to */
+/* registers etc. */
+{
+ int typ=p->typf,typ1,reg,c=p->code;
+
+ typ=q1typ(p);
+ if(ISPOINTER(typ)) typ=(UNSIGNED|LONG);
+
+ q1reg=q2reg=zreg=0;
+ if(p->q1.flags®) q1reg=p->q1.reg;
+ if(p->q2.flags®) q2reg=p->q2.reg;
+ if((p->z.flags&(REG|DREFOBJ))==REG) zreg=p->z.reg;
+
+
+ if((p->q1.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q1.val,typ);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+ if(ISFLOAT(typ)) q1reg=f31; else q1reg=r31;
+ }else{
+ if(ISFLOAT(typ)) reg=f1; else reg=t1;
+ if(c==ASSIGN&&zreg) reg=zreg;
+ if(c==SETRETURN&&p->z.reg) reg=p->z.reg;
+ if((c==MOD||c==DIV)&&ISINT(typ)&&!regs[25]) reg=25; /* Linux-div */
+ if(ISFLOAT(typ)||c==DIV||c==SUB||c==ASSIGN||c==PUSH||c==SETRETURN||c==LSHIFT||c==RSHIFT||c==COMPARE){
+ load_reg(f,reg,&p->q1,typ,t1);
+ q1reg=reg;
+ }else{
+ if(ISINT(typ)){
+ if(!zumleq(vumax,ul2zum(255UL))||!zmleq(vmax,l2zm(255L))||zmleq(vmax,l2zm(-1L))){
+ load_reg(f,reg,&p->q2,typ,t1);
+ q1reg=reg;
+ }
+ }
+ }
+ }
+ }else if(c!=ADDRESS){
+ if(p->q1.flags&&!q1reg){
+ if(ISFLOAT(typ)) reg=f1; else reg=t1;
+ if((c==ASSIGN||c==CONVERT)&&zreg&&(reg-r31)*(zreg-r31)>0) reg=zreg;
+ if(c==SETRETURN&&p->z.reg) reg=p->z.reg;
+ if((p->q1.flags&DREFOBJ)||c==ADDI2P||c==SUBIFP) {typ1=POINTER;reg=t1;} else typ1=typ;
+ if(c==CALL) reg=vp;
+ if((c==MOD||c==DIV)&&ISINT(typ1)&&!regs[25]) reg=25; /* Linux-div */
+ if(ISSCALAR(typ1)){
+ int m=p->q1.flags;
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,reg,&p->q1,typ1,t1);
+ p->q1.flags=m;
+ q1reg=reg;
+ }
+ }
+ if((p->q1.flags&DREFOBJ)&&ISSCALAR(typ)){
+ if(ISFLOAT(typ)) reg=f1; else reg=t1;
+ if((c==ASSIGN||c==CONVERT)&&zreg&®ok(zreg,typ,0)) reg=zreg;
+ if(c==SETRETURN&&p->z.reg) reg=p->z.reg;
+ if((c==MOD||c==DIV)&&(typ&NQ)<=LONG&&!regs[25]) reg=25; /* Linux-div */
+ if(c==ADDI2P||c==SUBIFP)
+ load_reg(f,reg,cam(IMM_IND,q1reg,-1,0),POINTER,t1);
+ else
+ load_reg(f,reg,cam(IMM_IND,q1reg,-1,0),typ,t1);
+ q1reg=reg;
+ }
+ }
+ typ=q2typ(p);
+ if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,typ);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+ if(ISFLOAT(typ)) q2reg=f31; else q2reg=r31;
+ }else{
+ if(ISFLOAT(typ)) reg=f2; else reg=t2;
+ if((c==MOD||c==DIV)&&ISINT(typ)&&!regs[26]) reg=26; /* Linux-div */
+ if(ISFLOAT(typ)){
+ load_reg(f,reg,&p->q2,typ,t2);
+ q2reg=reg;
+ }else{
+ if(ISINT(typ)){
+ if(!zumleq(vumax,ul2zum(255UL))||!zmleq(vmax,l2zm(255L))||zmleq(vmax,l2zm(-1L))){
+ load_reg(f,reg,&p->q2,typ,t2);
+ q2reg=reg;
+ }
+ }
+ }
+ }
+ }else{
+ if(p->q2.flags&&!q2reg){
+ if(p->q2.flags&DREFOBJ) typ1=POINTER; else typ1=typ;
+ if(ISFLOAT(typ1)) reg=f2; else reg=t2;
+ if((c==MOD||c==DIV)&&ISINT(typ1)&&!regs[26]) reg=26; /* Linux-div */
+ if(ISSCALAR(typ1)){
+ int m=p->q2.flags;
+ p->q2.flags&=~DREFOBJ;
+ load_reg(f,reg,&p->q2,typ1,t2);
+ p->q2.flags=m;
+ q2reg=reg;
+ }
+ }
+ if((p->q2.flags&DREFOBJ)&&ISSCALAR(typ)){
+ if(ISFLOAT(typ)) reg=f2; else reg=t2;
+ if((c==MOD||c==DIV)&&ISINT(typ)&&!regs[26]) reg=26; /* Linux-div */
+ load_reg(f,reg,cam(IMM_IND,q2reg,-1,0),typ,t2);
+ q2reg=reg;
+ }
+ }
+ if(p->z.flags&&!isreg(z)){
+ typ=ztyp(p);
+ if(ISFLOAT(typ)) zreg=f3; else zreg=t3;
+ if((c==MOD||c==DIV)&&ISINT(typ)&&!regs[28]) zreg=28; /* Linux-div */
+ }
+ if(q1reg){ p->q1.flags=REG; p->q1.reg=q1reg;}
+ if(q2reg){ p->q2.flags=REG; p->q2.reg=q2reg;}
+ return p;
+}
+static long pof2(zumax x)
+/* Yields log2(x)+1 oder 0. */
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=64&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+static void pr(FILE *f,struct IC *p)
+/* Writes the destination register to the real destination if necessary. */
+{
+ int typ=p->typf;
+ if(p->z.flags){
+ if(p->code==ADDRESS||p->code==ADDI2P||p->code==SUBIFP) typ=POINTER;
+ if(!isreg(z)){
+ if(p->z.flags&DREFOBJ){
+ if(p->z.flags®){
+ store_reg(f,zreg,cam(IMM_IND,p->z.reg,-1,0),typ);
+ }else{
+ int r,m;
+ if(t1==zreg) r=t2; else r=t1;
+ m=p->z.flags;
+ p->z.flags&=~DREFOBJ;
+ load_reg(f,r,&p->z,POINTER,r);
+ p->z.flags=m;
+ store_reg(f,zreg,cam(IMM_IND,r,balign(&p->z),0),typ);
+ }
+ }else{
+ store_reg(f,zreg,&p->z,typ);
+ }
+ }else{
+ if(p->z.reg!=zreg)
+ move_reg(f,zreg,p->z.reg);
+ }
+ }
+}
+
+static void probj2(FILE *f,struct obj *p,int t)
+/* Prints an object. */
+{
+ if(p->am){
+ if(p->am->flags==REG_IND) ierror(0);
+ if(p->am->flags==IMM_IND) emit(f,"%ld(%s)",p->am->offset,regnames[p->am->base]);
+ return;
+ }
+ if(p->flags&DREFOBJ) emit(f,"(");
+ if(p->flags&VAR) {
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+ if(p->flags®){
+ emit(f,"%s",regnames[p->reg]);
+ }else{
+ long of=zm2l(p->v->offset);
+ if(of>=0)
+ of+=frameoffset+zm2l(p->val.vmax);
+ else
+ of=-of-zm2l(maxalign)+framesize+zm2l(p->val.vmax);
+ if(of>32767) ierror(0);
+ emit(f,"%ld(%s)",of,regnames[sp]);
+ }
+ }else{
+ if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,MAXINT);emit(f,"+");}
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ }
+ }
+ if((p->flags®)&&!(p->flags&VAR)) emit(f,"%s",regnames[p->reg]);
+ if(p->flags&KONST){
+ emitval(f,&p->val,t&NU);
+ }
+ if(p->flags&DREFOBJ) emit(f,")");
+}
+static void dwarf2_print_frame_location(FILE *f,struct Var *v)
+{
+ struct obj o;
+ o.flags=REG;
+ /*FIXME: need correct register translation */
+ o.reg=sp;
+ o.val.vmax=l2zm(0L);
+ o.v=0;
+ dwarf2_print_location(f,&o);
+}
+static int dwarf2_regnumber(int r)
+{
+ /*FIXME: needs correct translation */
+ return r-1;
+}
+static zmax dwarf2_fboffset(struct Var *v)
+{
+ long of;
+ if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0);
+ of=zm2l(v->offset);
+ if(of>=0)
+ of+=frameoffset;
+ else
+ of=-of-zm2l(maxalign)+framesize;
+ if(of>32767) ierror(0);
+ return l2zm(of);
+}
+static void function_top(FILE *f,struct Var *v,long offset,long maxpushed)
+/* Generates function top. */
+{
+ int i;
+ emit(f,"\t.set\tnoat\n");
+ if(section!=CODE){emit(f,codename);if(f) section=CODE;}
+ emit(f,"\t.align\t3\n");
+ if(v->storage_class==EXTERN)
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ emit(f,"\t.ent\t%s%s\n",idprefix,v->identifier);
+ if(v->storage_class==STATIC)
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ else
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ if(function_calls) emit(f,"\tldgp\t%s,0(%s)\n",regnames[gp],regnames[vp]);
+ if(v->storage_class==STATIC)
+ emit(f,"%s%ld..ng:\n",labprefix,zm2l(v->offset));
+ else
+ emit(f,"%s%s..ng:\n",idprefix,v->identifier);
+ framesize=offset+maxpushed;
+ if(function_calls) framesize+=8; /* lr */
+ for(i=1;i<=MAXR;i++)
+ if(regused[i]&&!regscratch[i]&&!regsa[i])
+ framesize+=8;
+ framesize=((framesize+16-1)/16)*16;
+ if(framesize>32767) ierror(0);
+ if(framesize) emit(f,"\tlda\t%s,%ld(%s)\n",regnames[sp],-framesize,regnames[sp]);
+ emit(f,"\t.frame\t%s,%ld,%s,0\n",regnames[sp],framesize,regnames[lr]);
+ frameoffset=maxpushed;
+ if(function_calls){
+ emit(f,"\tstq\t%s,%ld(%s)\n",regnames[lr],frameoffset,regnames[sp]);
+ frameoffset+=8;
+ }
+ for(i=1;i<=MAXR;i++){
+ if(regused[i]&&!regscratch[i]&&!regsa[i]){
+ if(i<=32){
+ emit(f,"\tstq\t%s,%ld(%s)\n",regnames[i],frameoffset,regnames[sp]);
+ }else{
+ emit(f,"\tstt\t%s,%ld(%s)\n",regnames[i],frameoffset,regnames[sp]);
+ }
+ frameoffset+=8;
+ }
+ }
+ emit(f,"\t.mask\t0x4000000,%ld\n",-framesize);
+ emit(f,"\t.prologue\t%c\n",function_calls?'1':'0');
+}
+static void function_bottom(FILE *f,struct Var *v,long offset,long maxpushed)
+/* Generates function bottom. */
+{
+ int i;
+ frameoffset=maxpushed;
+ if(function_calls){
+ emit(f,"\tldq\t%s,%ld(%s)\n",regnames[lr],frameoffset,regnames[sp]);
+ frameoffset+=8;
+ }
+ for(i=1;i<=MAXR;i++){
+ if(regused[i]&&!regscratch[i]&&!regsa[i]){
+ if(i<=32){
+ emit(f,"\tldq\t%s,%ld(%s)\n",regnames[i],frameoffset,regnames[sp]);
+ }else{
+ emit(f,"\tldt\t%s,%ld(%s)\n",regnames[i],frameoffset,regnames[sp]);
+
+ }
+ frameoffset+=8;
+ }
+ }
+ if(framesize) emit(f,"\tlda\t%s,%ld(%s)\n",regnames[sp],framesize,regnames[sp]);
+ emit(f,"\tret\t%s,(%s),1\n",regnames[r31],regnames[lr]);
+ emit(f,"\t.end\t%s%s\n",idprefix,v->identifier);
+ emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+ emit(f,"\t.size\t%s%s,$-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
+}
+static int balign(struct obj *o)
+/* Liefert die unteren 3 Bits des Objekts. -1 wenn unklar. */
+{
+ int sc;
+ if(o->flags&DREFOBJ) return -1;
+ if(o->am) return o->am->align;
+ if(!(o->flags&VAR)) ierror(0);
+ sc=o->v->storage_class;
+ if(sc==EXTERN||sc==STATIC){
+ /* Alle statischen Daten werden vom cg auf 64bit alignt. */
+ return zm2l(zmand(o->val.vmax,l2zm(7L)));
+ }
+ if(sc==AUTO||sc==REGISTER){
+ zmax of=o->v->offset;
+ if(!zmleq(l2zm(0L),of))
+ of=zmsub(l2zm(0L),zmadd(of,maxalign));
+ return zm2l(zmand(zmadd(of,o->val.vmax),l2zm(7L)));
+ }
+ ierror(0);
+}
+
+/* Routinen fuer Debug-Informationen mit stabs. */
+
+static int debug_blabel,debug_elabel;
+static int debug_type(FILE *,struct Typ *);
+static void debug_init(FILE *,struct Var *);
+static void debug_exit(FILE *,struct Var *);
+static void debug_var(FILE *,struct obj *);
+static void debug_IC(FILE *,struct IC *);
+static void debug_cleanup(FILE *);
+
+static int debug_type(FILE *f,struct Typ *t)
+ /* Liefert Typindex. */
+{
+ return t->flags&NU;
+}
+static void debug_init(FILE *f,struct Var *v)
+ /* Debug-Infos. Wird am Anfang von gen_code aufgerufen. */
+{
+ static int did_header;
+ if(!did_header){
+ emit(f,"\t.stabs \"\",100,0,0,%stext0\n",labprefix);
+ emit(f,"\t.stabs \"%s\",100,0,0,%stext0\n",filename,labprefix);
+ emit(f,"\t.text\n%stext0:\n",labprefix);if(f) section=CODE;
+ emit(f,"\t.stabs\t\"char:t%d=r1;-128;127;\",128,0,0,0\n",CHAR);
+ emit(f,"\t.stabs\t\"short:t%d=r1;-32768;32767;\",128,0,0,0\n",SHORT);
+ emit(f,"\t.stabs\t\"int:t%d=r1;-2147483648;2147483647;\",128,0,0,0\n",INT);
+ emit(f,"\t.stabs\t\"long:t%d=r1;001000000000000000000000;000777777777777777777777;\",128,0,0,0\n",LONG);
+ emit(f,"\t.stabs\t\"unsigned char:t%d=r1;0;255;\",128,0,0,0\n",UNSIGNED|CHAR);
+ emit(f,"\t.stabs\t\"unsigned short:t%d=r1;0;65535;\",128,0,0,0\n",UNSIGNED|SHORT);
+ emit(f,"\t.stabs\t\"unsigned int:t%d=r1;0;-1;\",128,0,0,0\n",UNSIGNED|INT);
+ emit(f,"\t.stabs\t\"unsigned long:t%d=r1;0;-1;\",128,0,0,0\n",UNSIGNED|LONG);
+ emit(f,"\t.stabs\t\"float:t%d=r1;4;0;\",128,0,0,0\n",FLOAT);
+ emit(f,"\t.stabs\t\"double:t%d=r1;8;0;\",128,0,0,0\n",DOUBLE);
+ emit(f,"\t.stabs\t\"void:t%d=%d;8;0;\",128,0,0,0\n",VOID,VOID);
+ did_header=1;
+ }
+ emit(f,"\t.stabs\t\"%s:F%d\",36,0,0,%s%s\n",v->identifier,debug_type(f,v->vtyp->next),idprefix,v->identifier);
+ debug_blabel=++label;debug_elabel=++label;
+}
+static void debug_exit(FILE *f,struct Var *v)
+ /* Debug-Infos. Wird am Ende von gen_code aufgerufen. */
+{
+ struct IC *p;
+ ierror(0);
+ emit(f,"\t.stabn\t192,0,0,%s%d\n",labprefix,debug_blabel);
+ emit(f,"\t.stabn\t224,0,0,%s%d\n",labprefix,debug_elabel);
+ for(p=first_ic;p;p=p->next){
+ if(p->q1.flags&VAR) debug_var(f,&p->q1);
+ if(p->q2.flags&VAR) debug_var(f,&p->q2);
+ if(p->z.flags&VAR) debug_var(f,&p->z);
+ }
+}
+static void debug_var(FILE *f,struct obj *o)
+ /* Debug-Infos fuer eine Variable ausgeben. */
+{
+ struct Var *v=o->v; int td;
+ if(!*v->identifier) return;
+ td=debug_type(f,v->vtyp);
+ if(ISFUNC(td)) return;
+ if(o->flags®){
+ emit(f,"\t.stabs\t\"%s:r%d\",0x40,0,0,%d\n",v->identifier,td,o->reg-1);
+ return;
+ }
+ if(v->storage_class==AUTO||v->storage_class==REGISTER){
+ long of=zm2l(v->offset);
+ if(!zmleq(l2zm(0L),v->offset)){
+ of=-of-zm2l(maxalign)+framesize;
+ emit(f,"#\toffset %ld:\n",of);
+ emit(f,"\t.stabs\t\"%s:p%d\",0x80,0,0,%ld\n",v->identifier,td,of-framesize);
+ }else{
+ of+=frameoffset;
+ emit(f,"#\toffset %ld:\n",of);
+ emit(f,"\t.stabs\t\"%s:%d\",0x80,0,0,%ld\n",v->identifier,td,of-framesize);
+ }
+ return;
+ }
+ ierror(td);
+}
+static void debug_IC(FILE *f,struct IC *p)
+ /* Debug-Infos. Wird fuer jedes IC aufgerufen. */
+{
+ static int lastline;int lab;
+ printf("%d",p->line);pric2(stdout,p);
+ if(!p->prev)
+ emit(f,"%s%d:\n",labprefix,debug_blabel);
+/* if(p->q1.flags&VAR) debug_var(f,&p->q1); */
+/* if(p->q2.flags&VAR) debug_var(f,&p->q2); */
+/* if(p->z.flags&VAR) debug_var(f,&p->z); */
+ if(p->line&&p->line!=lastline){
+ lab=++label;lastline=p->line;
+ emit(f,"%s%d:\n",labprefix,lab);
+ emit(f,"\t.stabn\t68,0,%d,%s%d\n",lastline,labprefix,lab);
+ }
+ if(!p->next) emit(f,"%s%d:\n",labprefix,debug_elabel);
+}
+static void debug_cleanup(FILE *f)
+ /* Debug-Infos. Wird in cleanup_cg aufgerufen. */
+{
+}
+
+
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+
+int init_cg(void)
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(8L);
+ char_bit=l2zm(8L);
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+ for(i= 1;i<=32;i++) {regsize[i]=l2zm(8L);regtype[i]=<yp;}
+ for(i=33;i<=64;i++) {regsize[i]=l2zm(8L);regtype[i]=<yp;}
+
+ /* Use multiple ccs. */
+ multiple_ccs=0; /* not yet */
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[LONG]=t_min[LLONG];
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=ul2zum(2147483647UL);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[LONG]=t_max[LLONG];
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=ul2zum(4294967295UL);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[LONG]=tu_max[LLONG];
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ /* This is not optimal but simple. */
+ regsa[t1]=regsa[t2]=regsa[t3]=regsa[t4]=regsa[t5]=1;
+ regsa[f1]=regsa[f2]=regsa[f3]=1;
+ regsa[sp]=regsa[gp]=regsa[sd]=1;
+ regsa[lr]=regsa[r31]=regsa[f31]=1;
+ regscratch[t1]=regscratch[t2]=regscratch[t3]=regscratch[t4]=regscratch[t5]=0;
+ regscratch[f1]=regscratch[f2]=regscratch[f3]=0;
+ regscratch[sp]=regscratch[gp]=regscratch[sd]=0;
+ regscratch[lr]=regscratch[r31]=regscratch[f31]=0;
+ /* reserve at - noch aendern */
+ /* regsa[29]=1;regscratch[29]=0; */
+ /* Debug stabs? */
+ stabs=(g_flags[5]&USEDFLAG);
+ target_macros=marray;
+ return 1;
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+/* A pointer MUST be returned in a register. The code-generator */
+/* has to simulate a pseudo register if necessary. */
+{
+ if(ISFLOAT(t->flags)) return 33;
+ if(ISSTRUCT(t->flags)||ISUNION(t->flags)) return 0;
+ if(zmleq(szof(t),l2zm(8L)))
+ return 1;
+ else
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ return 0;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(r==0) return 0;
+ if(t==0) return 0;
+ if(ISFLOAT(t)){
+ if(r>=33&&r<=64)
+ return 1;
+ else
+ return 0;
+ }
+ if(ISSCALAR(t)&&r>=1&&r<=32) return 1;
+ return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!(p->q2.flags&KONST))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* On the PowerPC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op=o&NQ,tp=t&NQ;
+ if((op==LONG||op==LLONG||op==POINTER)&&(tp==LONG||tp==LLONG||tp==POINTER)) return 0;
+ if((op==DOUBLE||op==LDOUBLE)&&(tp==DOUBLE||tp==LDOUBLE)) return 0;
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ title(f);
+ if(newobj){
+ size=zmmult(zmdiv(zmadd(size,l2zm(7L)),l2zm(8L)),l2zm(8L));
+ emitzm(f,size);
+ }else{
+ emit(f,"\t.zero\t");
+ emitzm(f,size);
+ }
+ emit(f,"\n");
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ title(f);
+ if(zm2l(align)>1)
+ emit(f,"\t.align\t3\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;
+ title(f);
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset));
+ emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp)));
+ if(section!=BSS)
+ emit(f,"\t.align\t3\n%s%ld:\n",labprefix,zm2l(v->offset));
+ else{
+ emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+ newobj=1;
+ }
+ }
+ if(v->storage_class==EXTERN){
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ if(v->flags&(DEFINED|TENTATIVE)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
+ emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp)));
+ if(section!=BSS)
+ emit(f,"\t.align\t3\n%s%s:\n",idprefix,v->identifier);
+ else{
+ emit(f,"\t.comm\t%s%s,",idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ title(f);
+ if(ISPOINTER(t)) t=UNSIGNED|LONG;
+ emit(f,"\t.%s\t",dct[t&NQ]);
+ if(!p->tree){
+ if(ISFLOAT(t)){
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+ if((t&NQ)!=FLOAT){
+ emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+ }
+ }else{
+ emitval(f,&p->val,t&NU);
+ }
+ }else{
+ if(p->tree->o.am) ierror(9);
+ probj2(f,&p->tree->o,t&NU);
+ }
+ emit(f,"\n");newobj=0;
+}
+
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/* The main code-generation. */
+{
+ int addbuf,c,t,cmpreg,cmpflag,wasnoreg,i,varargs=0,fixargs;struct IC *m;
+ long pushed,maxpushed;
+ if(DEBUG&1) printf("gen_code()\n");
+ if(stabs) debug_init(f,v);
+ for(c=1;c<=MAXR;c++){regs[c]=regsa[c];st[c]=ESGN;}
+ /* We do a pass over the code to retrieve some info and prepare certain optimizations */
+ addbuf=0;maxpushed=0;
+ title(f);
+ for(m=p;m;m=m->next){
+ c=m->code;t=m->typf&NU;
+ if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
+ if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
+ if(c==COMPARE&&(m->q2.flags&KONST)){
+ eval_const(&m->q2.val,t);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+ m->q2.flags=0;m->code=c=TEST;
+ }
+ }
+ if(ISINT(t)&&(m->q2.flags&KONST)&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+ eval_const(&m->q2.val,t);
+ i=pof2(vumax);
+ if(i){
+ if(c==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ m->code=AND;
+ }else{
+ vmax=l2zm(i-1);
+ if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+ }
+ c=m->code;
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ if(c==AND){
+ insert_const(&m->q2.val,t&NU);
+ }else{
+ insert_const(&m->q2.val,INT);
+ p->typf2=INT;
+ }
+ }
+ }
+ /* Need one stack slot for transfrring between integer and floating-point registers. */
+ t&=NQ;
+ if(c==CONVERT&&addbuf<8&&((ISFLOAT(t)&&!ISFLOAT(m->typf2))||(!ISFLOAT(t)&&ISFLOAT(p->typf2)))) addbuf=8;
+ /* May need one stack slot for inline memcpy. */
+/* if((c==ASSIGN||c==PUSH)&&t>=POINTER&&addbuf<8) addbuf=8; */
+ /* Need additional stack slots for passing function arguments. */
+ if(c==CALL&&maxpushed<zm2l(m->q2.val.vmax)) maxpushed=zm2l(m->q2.val.vmax);
+ if(c==CALL&&(m->q1.flags&VAR)&&!strcmp(m->q1.v->identifier,"__va_start")) varargs=1;
+ /* Need up to 4 stack slots for calling div/mod-functions. */
+ if((c==DIV||c==MOD)&&ISINT(t)&&addbuf<32){
+ if(regs[25]||regs[26]||regs[28]||regs[29]) addbuf=32;
+ }
+ }
+ /* Noch nicht ok. */
+ if(varargs){
+ fixargs=0;
+ for(i=0;i<v->vtyp->exact->count;i++){
+ c=(*v->vtyp->exact->sl)[i].styp->flags;
+ if(ISPOINTER(c)) fixargs++;
+ }
+ if(fixargs<6) addbuf+=(6-fixargs)*16;
+ }
+ function_top(f,v,zm2l(offset+addbuf),maxpushed);
+ if(varargs){
+ for(i=fixargs+1;i<=6;i++){
+ emit(f,"\tstq\t%s,%ld(%s)\n",regnames[16+i],framesize-(7-i)*16,regnames[sp]);
+ emit(f,"\tstt\t%s,%ld(%s)\n",regnames[48+i],framesize-(7-i)*16+8,regnames[sp]);
+ }
+ }
+ pushed=0;
+ for(;p;pr(f,p),p=p->next){
+ if(DEBUG) pric2(stdout,p);
+ if(debug_info){
+ if(stabs)
+ debug_IC(f,p);
+ else
+ dwarf2_line_info(f,p);
+ }
+ c=p->code;t=p->typf;
+ if(c==NOP) continue;
+ if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
+ if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
+ if(c==LABEL||(c>=BEQ&&c<=BRA)){
+ int i;
+ for(i=1;i<=32;i++)
+ if(regs[i]&&!regsa[i]) extend(f,i);
+ }
+ if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);continue;}
+ if(c==BRA) {emit(f,"\tbr\t%s%d\n",labprefix,t);continue;}
+ if(c>=BEQ&&c<BRA){
+ if(cmpflag){
+ emit(f,"\t%sb%s\t%s,%s%d\n",cmpreg<=32?"":"f",cmpflag<0?"eq":"ne",regnames[cmpreg],labprefix,t);
+ }else{
+ emit(f,"\t%sb%s\t%s,%s%d\n",cmpreg<=32?"":"f",ccs[c-BEQ],regnames[cmpreg],labprefix,t);
+ }
+ continue;
+ }
+ if(c==MOVETOREG){
+ load_reg(f,p->z.reg,&p->q1,p->z.reg<=32?LONG:DOUBLE,0);
+ p->z.flags=0;
+ continue;
+ }
+ if(c==MOVEFROMREG){
+ store_reg(f,p->q1.reg,&p->z,p->q1.reg<=32?LONG:DOUBLE);
+ p->z.flags=0;
+ continue;
+ }
+ if(ISPOINTER(t)) t=((t&~NU)|UNSIGNED|LONG);
+ if((c==ASSIGN||c==PUSH)&&(!ISSCALAR(t)||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+ zmax size; struct obj loops;
+ int salign,dalign,cl,a1,a2,mr,ms;
+ size=p->q2.val.vmax;
+ salign=balign(&p->q1);
+ if(c==PUSH) dalign=0; else dalign=balign(&p->z);
+ if(salign>=0&&dalign>=0&&(salign&3)==(dalign&3)){
+ a1=t1; a2=t2;
+ }else{
+ if(!helpl) helpl=++label;
+ cl=0;mr=0;ms=0;
+ for(i=1;i<=32;i++){
+ if(i!=17&&i!=18&&i!=19&®used[i]&&!regscratch[i]&&!regs[i]) mr=i;
+ if(regs[i]&®scratch[i]) ms=1;
+ }
+ if(mr==0) mr=t3;
+ if(regs[17]||regs[18]||regs[19]||function_calls==0) ms=1;
+ if(ms) emit(f,"\tlda\t%s,%s%d\n",regnames[mr],labprefix,helpl);
+ if(regs[17]) emit(f,"\tstq\t%s,%d(%s)\n",regnames[17],8*cl++,regnames[mr]);
+ if(regs[18]) emit(f,"\tstq\t%s,%d(%s)\n",regnames[18],8*cl++,regnames[mr]);
+ if(regs[19]) emit(f,"\tstq\t%s,%d(%s)\n",regnames[19],8*cl++,regnames[mr]);
+ a1=18;a2=17;
+ if(p->z.am&&p->z.am->base==18) ierror(0);
+ if(!p->z.am&&(p->z.flags®)&&p->z.reg==18) ierror(0);
+ }
+ if(p->q1.flags&DREFOBJ){
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,a1,&p->q1,POINTER,a1);
+ p->q1.flags|=DREFOBJ;
+ }else{
+ load_address(f,a1,&p->q1,POINTER);
+ }
+ if(p->z.flags&DREFOBJ){
+ p->z.flags&=~DREFOBJ;
+ load_reg(f,a2,&p->z,POINTER,a2);
+ p->z.flags|=DREFOBJ;
+ }else{
+ if(c==PUSH){
+ emit(f,"\tlda\t%s,%ld(%s)\n",regnames[a2],pushed,regnames[sp]);
+ pushed+=zm2l(p->q2.val.vmax);
+ }else{
+ load_address(f,a2,&p->z,POINTER);
+ }
+ }
+ if(salign>=0&&dalign>=0&&(salign&3)==(dalign&3)){
+ int do64,m,s;
+ if((salign&7)==(dalign&7))
+ {do64=1;m=8;s='q';}
+ else
+ {do64=0;m=4;s='l';salign&=3;}
+ if(salign&7){
+ emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t3],-salign,regnames[t1]);
+ emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t4],-salign,regnames[t2]);
+ cl=(1<<salign)-1;
+ if(!zmleq(l2zm(m-salign),size)) cl+=((1<<(m-salign-zm2l(size)))-1)<<(salign+zm2l(size));
+ emit(f,"\tzap\t%s,%d,%s\n",regnames[t3],cl,regnames[t3]);
+ emit(f,"\tzapnot\t%s,%d,%s\n",regnames[t4],cl,regnames[t4]);
+ emit(f,"\tbis\t%s,%s,%s\n",regnames[t3],regnames[t4],regnames[t3]);
+ emit(f,"\tst%c\t%s,%d(%s)\n",s,regnames[t3],-salign,regnames[t2]);
+ size=zmsub(size,zm2l(m-salign));
+ salign=m-salign;
+ }else
+ salign=0;
+ loops.val.vmax=zmdiv(size,l2zm(8*m));
+ if(zmleq(l2zm(2L),loops.val.vmax)){
+ loops.flags=KONST;
+ loops.am=0;
+ load_reg(f,t3,&loops,LONG,t3);
+ cl=++label;
+ emit(f,"\t.align\t4\n%s%d:\n",labprefix,cl);
+ }
+ if(!zmeqto(loops.val.vmax,l2zm(0))){
+ for(i=0;i<8;i+=2){
+ emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t1]);
+ emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t5],salign+i*m+m,regnames[t1]);
+ emit(f,"\tst%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t2]);
+ emit(f,"\tst%c\t%s,%d(%s)\n",s,regnames[t5],salign+i*m+m,regnames[t2]);
+ }
+ }
+ if(zmleq(l2zm(2L),loops.val.vmax)){
+ emit(f,"\taddq\t%s,%d,%s\n",regnames[t1],8*m,regnames[t1]);
+ emit(f,"\taddq\t%s,%d,%s\n",regnames[t2],8*m,regnames[t2]);
+ emit(f,"\tsubq\t%s,1,%s\n",regnames[t3],regnames[t3]);
+ emit(f,"\tbne\t%s,%s%d\n",regnames[t3],labprefix,cl);
+ }else{
+ if(!zmeqto(loops.val.vmax,l2zm(0L)))
+ salign+=8*m;
+ }
+ size=zmand(size,l2zm(8*m-1));
+ for(i=0;i<(zm2l(size)/m/2)*2;i+=2){
+ emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t1]);
+ emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t5],salign+i*m+m,regnames[t1]);
+ emit(f,"\tst%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t2]);
+ emit(f,"\tst%c\t%s,%d(%s)\n",s,regnames[t5],salign+i*m+m,regnames[t2]);
+ }
+ size=zmand(size,l2zm(2*m-1));
+ if(zm2l(size)>=m){
+ emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t1]);
+ emit(f,"\tst%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t2]);
+ size=zmsub(size,l2zm(m));i++;
+ }
+ if(zm2l(size)>0){
+ if(zm2l(size)==4){
+ emit(f,"\tldl\t%s,%d(%s)\n",regnames[t4],salign+i*m,regnames[t1]);
+ emit(f,"\tstl\t%s,%d(%s)\n",regnames[t4],salign+i*m,regnames[t2]);
+ }else{
+ emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t1]);
+ emit(f,"\tld%c\t%s,%d(%s)\n",s,regnames[t5],salign+i*m,regnames[t2]);
+ cl=(1<<zm2l(size))-1;
+ emit(f,"\tzapnot\t%s,%d,%s\n",regnames[t4],cl,regnames[t4]);
+ emit(f,"\tzap\t%s,%d,%s\n",regnames[t5],cl,regnames[t5]);
+ emit(f,"\tbis\t%s,%s,%s\n",regnames[t4],regnames[t5],regnames[t4]);
+ emit(f,"\tst%c\t%s,%d(%s)\n",s,regnames[t4],salign+i*m,regnames[t2]);
+ }
+ }
+ p->z.flags=0; /* to prevent pr() from... */
+ continue;
+ }
+ for(i=1;i<=32;i++){
+ if(i!=17&&i!=18&&i!=19&®s[i]&®scratch[i])
+ emit(f,"\tstq\t%s,%d(%s)\n",regnames[i],8*cl++,regnames[mr]);
+ }
+ if(function_calls==0) emit(f,"\tstq\t%s,%d(%s)\n",regnames[lr],8*cl++,regnames[mr]);
+ if(cl>helps) helps=cl;
+ loops.val.vmax=size;
+ loops.flags=KONST;
+ loops.am=0;
+ load_reg(f,19,&loops,LONG,19);
+ emit(f,"\t.global\t%smemcpy\n",idprefix);
+ emit(f,"\tjsr\t%s,%smemcpy\n",regnames[lr],idprefix);
+ emit(f,"\tldgp\t%s,0(%s)\n",regnames[gp],regnames[lr]);
+ cl=0;
+ if(ms&&mr==t3) emit(f,"\tlda\t%s,%s%d\n",regnames[mr],labprefix,helpl);
+ if(regs[17]) emit(f,"\tldq\t%s,%d(%s)\n",regnames[17],8*cl++,regnames[mr]);
+ if(regs[18]) emit(f,"\tldq\t%s,%d(%s)\n",regnames[18],8*cl++,regnames[mr]);
+ if(regs[19]) emit(f,"\tldq\t%s,%d(%s)\n",regnames[19],8*cl++,regnames[mr]);
+ for(i=1;i<=32;i++){
+ if(i!=17&&i!=18&&i!=19&®s[i]&®scratch[i])
+ emit(f,"\tldq\t%s,%d(%s)\n",regnames[i],8*cl++,regnames[mr]);
+ }
+ if(function_calls==0) emit(f,"\tldq\t%s,%d(%s)\n",regnames[lr],8*cl++,regnames[mr]);
+ p->z.flags=0;
+ continue;
+ }
+ if(isreg(q1)) wasnoreg=1; else wasnoreg=0;
+ p=do_refs(f,p);
+ c=p->code;
+ if(c==CONVERT){
+ int to;
+ to=p->typf2&NU;
+ if(ISPOINTER(to)) to=(UNSIGNED|LONG);
+ if(ISINT(to)&&ISINT(t)){
+ if((to&NQ)>=(t&NQ)){
+ if((t&NQ)<INT){
+ if(t&UNSIGNED){
+ emit(f,"\tzapnot\t%s,%d,%s\n",regnames[q1reg],(t&NQ)==CHAR?1:3,regnames[zreg]);
+ st[zreg]=EUNS;continue;
+ }else{
+ emit(f,"\tsext%c\t%s,%s\n",(t&NQ)==CHAR?'b':'w',regnames[q1reg],regnames[zreg]);
+ st[zreg]=ESGN;continue;
+ }
+ }
+ zreg=q1reg;
+ }else if((t&NQ)==LONG||(t&NQ)==LLONG){
+ if(to&UNSIGNED)
+ uextend(f,q1reg);
+ else
+ extend(f,q1reg);
+ st[q1reg]=ESGN;
+ zreg=q1reg;
+ }else{
+ if((to&UNSIGNED)==(t&UNSIGNED)){
+ zreg=q1reg;
+ }else{
+ if(to&UNSIGNED){
+ emit(f,"\tzapnot\t%s,%d,%s\n",regnames[q1reg],(t&NQ)==CHAR?1:3,regnames[zreg]);
+ st[zreg]=EUNS;continue;
+ }else{
+ emit(f,"\tsext%c\t%s,%s\n",(t&NQ)==CHAR?'b':'w',regnames[q1reg],regnames[zreg]);
+ st[zreg]=ESGN;continue;
+ }
+ }
+ }
+ continue;
+ }
+ if(ISFLOAT(to)){
+ st[zreg]=ESGN;
+ if(ISFLOAT(t)){
+ emit(f,"\tcvt%c%c\t%s,%s\n",x_t[to&NQ],x_t[t&NQ],regnames[q1reg],regnames[zreg]);
+ continue;
+ }
+/* if(t&UNSIGNED) ierror(0); */
+ emit(f,"\tcvttqc\t%s,%s\n",regnames[q1reg],regnames[f3]);
+/* emit(f,"\tftoit\t%s,%s\n",regnames[q1reg],regnames[zreg]); */
+/* emit(f,"\t.long\t%ld\n",(0x1cl<<26)+(0x70l<<5)+(31l<<16)+((long)(q1reg-33)<<21)+zreg-1); */
+ emit(f,"\tstt\t%s,%ld(%s)\n",regnames[f3],framesize-addbuf,regnames[sp]);
+ emit(f,"\tldq\t%s,%ld(%s)\n",regnames[zreg],framesize-addbuf,regnames[sp]);
+ st[zreg]=ESGN;
+ continue;
+ }
+ if(ISFLOAT(t)){
+/* if(to&UNSIGNED) ierror(0); */
+/* emit(f,"\titoft\t%s,%s\n",regnames[q1reg],regnames[zreg]); */
+ emit(f,"\tstq\t%s,%ld(%s)\n",regnames[q1reg],framesize-addbuf,regnames[sp]);
+ emit(f,"\tldt\t%s,%ld(%s)\n",regnames[zreg],framesize-addbuf,regnames[sp]);
+ emit(f,"\tcvtq%c\t%s,%s\n",x_t[t&15],regnames[zreg],regnames[zreg]);
+
+ continue;
+ }
+ }
+ if(c==KOMPLEMENT){
+ emit(f,"\tornot\t%s,%s,%s\n",regnames[r31],regnames[q1reg],regnames[zreg]);
+ if((t&NQ)==INT) st[zreg]=0; else st[zreg]=ESGN;
+ continue;
+ }
+ if(c==SETRETURN){
+ if(p->z.reg){
+ if(zreg==0) load_reg(f,p->z.reg,&p->q1,t,t3);
+ extend(f,p->z.reg);
+ }else
+ ierror(0);
+ continue;
+ }
+ if(c==GETRETURN){
+ if(p->q1.reg){
+ zreg=p->q1.reg;
+ st[zreg]=ESGN;
+ }else
+ p->z.flags=0;
+ continue;
+ }
+ if(c==CALL){
+ int reg;
+ if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ pushed-=zm2l(p->q2.val.vmax);
+ continue;
+ }
+ if((p->q1.flags&VAR)&&p->q1.v->storage_class==EXTERN&&!(g_flags[6]&USEDFLAG)){
+ char *s=p->q1.v->identifier;
+ if(!strcmp("abs",s)||!strcmp("labs",s)){
+ emit(f,"\tsubq\t%s,%s,%s\n",regnames[r31],regnames[17],regnames[1]);
+ emit(f,"\tcmovge\t%s,%s,%s\n",regnames[17],regnames[17],regnames[1]);
+ continue;
+ }
+ if(!strcmp("fabs",s)){
+ emit(f,"\tfabs\t%s,%s\n",regnames[17],regnames[1]);
+ continue;
+ }
+ if(!strcmp("__va_fixargs",s)){
+ emit(f,"\tlda\t%s,%d(%s)\n",regnames[1],fixargs,regnames[r31]);
+ continue;
+ }
+ if(!strcmp("__va_start",s)){
+ emit(f,"\tlda\t%s,%ld(%s)\n",regnames[1],framesize-(6-fixargs)*16,regnames[sp]);
+ continue;
+ }
+ }
+ for(reg=17;reg<=22;reg++)
+ extend(f,reg);
+ if(q1reg){
+ if(q1reg!=vp) move_reg(f,q1reg,vp);
+ emit(f,"\tjsr\t%s,(%s),0\n",regnames[lr],regnames[vp]);
+ }else{
+ emit(f,"\tjsr\t%s,",regnames[lr]);
+ probj2(f,&p->q1,t);emit(f,"\n");
+ }
+ emit(f,"\tldgp\t%s,0(%s)\n",regnames[gp],regnames[lr]);
+ pushed-=zm2l(p->q2.val.vmax);
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(t==0) ierror(0);
+ if(q1reg){
+ if(c==PUSH){
+ extend(f,q1reg);
+ if((t&NQ)==FLOAT){
+ emit(f,"\tcvtst\t%s,%s\n",regnames[q1reg],regnames[f1]);
+ q1reg=f1;
+ emit(f,"\tsts\t%s,%ld(%s)\n",regnames[q1reg],pushed,regnames[sp]);
+ }else{
+ emit(f,"\tst%c\t%s,%ld(%s)\n",q1reg<=32?'q':'t',regnames[q1reg],pushed,regnames[sp]);
+ }
+ pushed+=8;
+ continue;
+ }
+ if(c==ASSIGN) zreg=q1reg;
+ continue;
+ }else ierror(0);
+ }
+ if(c==ADDRESS){
+ load_address(f,zreg,&p->q1,POINTER);
+ continue;
+ }
+ if(c==MINUS){
+ if(ISINT(t))
+ emit(f,"\tsub%c\t%s,%s,%s\n",x_t[t&NQ],regnames[r31],regnames[q1reg],regnames[zreg]);
+ else
+ emit(f,"\tsub%c\t%s,%s,%s\n",x_t[t&NQ],regnames[f31],regnames[q1reg],regnames[zreg]);
+ st[zreg]=ESGN;
+ continue;
+ }
+ if(c==TEST){
+ if(st[q1reg]==0) extend(f,q1reg);
+ cmpreg=q1reg;
+ cmpflag=0;
+ continue;
+ }
+ if(c==COMPARE){
+ struct IC *br=p->next;
+ while(1){
+ if(br->code>=BEQ&&br->code<BRA) break;
+ if(br->code!=FREEREG) ierror(0);
+ br=br->next;
+ }
+ if(ISFLOAT(t)) cmpreg=f3; else cmpreg=t3;
+ if(br->code==BEQ||br->code==BNE){
+ if((t&NU)==(UNSIGNED|INT)){
+ if(st[q1reg]==ESGN) extend(f,q2reg);
+ else if(st[q2reg]==ESGN) extend(f,q1reg);
+ else if(st[q1reg]==EUNS) uextend(f,q2reg);
+ else if(st[q2reg]==EUNS) uextend(f,q1reg);
+ else {extend(f,q1reg);extend(f,q2reg);}
+ }
+ if((t&NU)==INT){extend(f,q1reg);extend(f,q2reg);}
+ if(ISFLOAT(t)) emit(f,"\tsub%c\t%s,",x_t[t&NQ],regnames[q1reg]);
+ else emit(f,"\tsub%c\t%s,",x_t[t&NQ],regnames[q1reg]);
+ probj2(f,&p->q2,t);emit(f,",%s\n",regnames[cmpreg]);
+ cmpflag=0;st[cmpreg]=ESGN;
+ }else{
+ char *s="";
+ if(t&UNSIGNED) s="u";
+ if((t&NU)==(UNSIGNED|INT)){uextend(f,q1reg);uextend(f,q2reg);}
+ if((t&NU)==INT){extend(f,q1reg);extend(f,q2reg);}
+ if(ISFLOAT(t)) s="t";
+ if(br->code==BLT||br->code==BGE){
+ emit(f,"\tcmp%slt\t%s,",s,regnames[q1reg]);
+ probj2(f,&p->q2,t);emit(f,",%s\n",regnames[cmpreg]);
+ if(br->code==BGE) cmpflag=-1; else cmpflag=1;
+ }else{
+ emit(f,"\tcmp%sle\t%s,",s,regnames[q1reg]);
+ probj2(f,&p->q2,t);emit(f,",%s\n",regnames[cmpreg]);
+ if(br->code==BGT) cmpflag=-1; else cmpflag=1;
+ }
+ }
+ continue;
+ }
+ if(c>=OR&&c<=AND){
+ emit(f,"\t%s\t%s,",logicals[c-OR],regnames[q1reg]);
+ probj2(f,&p->q2,t);emit(f,",%s\n",regnames[zreg]);
+ /* hier ist mehr moeglich */
+ if((t&NQ)==INT) st[zreg]=0; else st[zreg]=ESGN;
+ continue;
+ }
+ if(c>=LSHIFT&&c<=MOD){
+ int xt;
+ if(c==LSHIFT&&(p->q2.flags&KONST)){
+ eval_const(&p->q2.val,t);
+ if(zumeqto(vumax,ul2zum(1UL))){
+ emit(f,"\tadd%c\t%s,%s,%s\n",x_t[t&NQ],regnames[q1reg],regnames[q1reg],regnames[zreg]);
+ st[zreg]=ESGN;continue;
+ }
+ if(zumeqto(vumax,ul2zum(2UL))){
+ emit(f,"\ts4add%c\t%s,0,%s\n",x_t[t&NQ],regnames[q1reg],regnames[zreg]);
+ st[zreg]=ESGN;continue;
+ }
+ if(zumeqto(vumax,ul2zum(3UL))){
+ emit(f,"\ts8add%c\t%s,0,%s\n",x_t[t&NQ],regnames[q1reg],regnames[zreg]);
+ st[zreg]=ESGN;continue;
+ }
+ }
+ if(c==RSHIFT||c==LSHIFT){
+ if(c==RSHIFT){
+ if(t&UNSIGNED){
+ if((t&NQ)<LONG) uextend(f,q1reg);
+ emit(f,"\tsrl\t");
+ }else{
+ extend(f,q1reg);
+ emit(f,"\tsra\t");
+ }
+ st[zreg]=st[q1reg];
+ }else{
+ emit(f,"\tsll\t");
+ if((t&NQ)<=INT) st[zreg]=0; else st[zreg]=ESGN;
+ }
+ emit(f,"%s,",regnames[q1reg]);
+ probj2(f,&p->q2,t);emit(f,",%s\n",regnames[zreg]);
+ continue;
+ }
+ if((c==DIV||c==MOD)&&ISINT(t)){
+ /* Linux-Routinen aufrufen. q1=$24 q2=$25 z=$27 $28 scratch */
+ if(!q1reg) ierror(0);
+ if(q1reg!=25){
+ if(regs[25]) emit(f,"\tstq\t%s,%ld(%s)\n",regnames[25],framesize-addbuf,regnames[sp]);
+ move_reg(f,q1reg,25);
+ }
+ if(q2reg!=26&®s[26]) emit(f,"\tstq\t%s,%ld(%s)\n",regnames[26],framesize-addbuf+8,regnames[sp]);
+ if(q2reg==25)
+ emit(f,"\tldq\t%s,%ld(%s)\n",regnames[26],framesize-addbuf,regnames[sp]);
+ else
+ load_reg(f,26,&p->q2,t,26);
+ if(zreg!=28&®s[28]) emit(f,"\tstq\t%s,%ld(%s)\n",regnames[28],framesize-addbuf+16,regnames[sp]);
+ if(regs[29]) emit(f,"\tstq\t%s,%ld(%s)\n",regnames[29],framesize-addbuf+24,regnames[sp]);
+ emit(f,"\t%sq%s\t%s,%s,%s\n",arithmetics[c-LSHIFT],(t&UNSIGNED)?"u":"",regnames[25],regnames[26],regnames[28]);
+ if(zreg!=28) move_reg(f,28,zreg);
+ if(q1reg!=25&®s[25]) emit(f,"\tldq\t%s,%ld(%s)\n",regnames[25],framesize-addbuf,regnames[sp]);
+ if(q2reg!=26&®s[26]) emit(f,"\tldq\t%s,%ld(%s)\n",regnames[26],framesize-addbuf+8,regnames[sp]);
+ if(zreg!=28&®s[28]) emit(f,"\tldq\t%s,%ld(%s)\n",regnames[28],framesize-addbuf+16,regnames[sp]);
+ if(regs[29]) emit(f,"\tldq\t%s,%ld(%s)\n",regnames[29],framesize-addbuf+24,regnames[sp]);
+ /* Was fuer st[zreg]? */
+ continue;
+ }
+ xt=x_t[t&NQ];
+ if((t&NQ)<INT) xt='l';
+ emit(f,"\t%s%c\t%s,",arithmetics[c-LSHIFT],xt,regnames[q1reg]);
+ probj2(f,&p->q2,t);emit(f,",%s\n",regnames[zreg]);
+ st[zreg]=ESGN;
+ continue;
+ }
+ if(c==SUBPFP){
+ emit(f,"\tsubq\t%s,%s,%s\n",regnames[q1reg],regnames[q2reg],regnames[zreg]);
+ st[zreg]=ESGN;continue;
+ }
+ if(c==ADDI2P||c==SUBIFP){
+ if(t&UNSIGNED){
+ if((t&NQ)<LONG) uextend(f,q2reg);
+ }else
+ extend(f,q2reg);
+ if(c==ADDI2P) emit(f,"\taddq\t%s,",regnames[q1reg]);
+ else emit(f,"\tsubq\t%s,",regnames[q1reg]);
+ probj2(f,&p->q2,t);
+ emit(f,",%s\n",regnames[zreg]);
+ st[zreg]=ESGN;continue;
+ }
+ ierror(0);
+ }
+ function_bottom(f,v,zm2l(offset+addbuf),maxpushed);
+ if(debug_info){
+ if(stabs){
+ debug_exit(f,v);
+ }else{
+ emit(f,"%s%d:\n",labprefix,++label);
+ dwarf2_function(f,v,label);
+ if(f) section=-1;
+ }
+ }
+}
+
+int shortcut(int code,int typ)
+{
+ return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *fkt)
+{
+ int f;
+ f=t->flags&NQ;
+ if(ISINT(f)||ISPOINTER(f)){
+ if(m->nextr>=6) return 0;
+ return 17+m->nextr++;
+ }
+ if(ISFLOAT(f)){
+ if(m->nextr>=6) return 0;
+ return 49+m->nextr++;
+ }
+ return 0;
+}
+void cleanup_cg(FILE *f)
+{
+ struct fpconstlist *p;
+ unsigned char *ip;
+
+ title(f);
+ if(f&&stabs) debug_cleanup(f);
+ while(p=firstfpc){
+ if(f){
+ int t=p->typ&NQ;
+ if(section!=CODE){emit(f,codename);if(f) section=CODE;}
+ emit(f,"\t.align\t3\n%s%d:\n\t",labprefix,p->label);
+ if(ISFLOAT(t)){
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"\t.long\t0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+ if((p->typ&NQ)!=FLOAT){
+ emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+ }
+ }else{
+ emit(f,"\t.quad\t");
+ emitval(f,&p->val,p->typ);
+ }
+ emit(f,"\n");
+ }
+ firstfpc=p->next;
+ free(p);
+ }
+ if(f&&helps) emit(f,"\t.lcomm\t%s%d,%d\n",labprefix,helpl,helps*8);
+}
+
+void init_db(FILE *f)
+{
+ if(!stabs){
+ dwarf2_setup(sizetab[POINTER],".byte",".2byte",".4byte",".8byte",labprefix,idprefix,".section");
+ dwarf2_print_comp_unit_header(f);
+ }
+}
+void cleanup_db(FILE *f)
+{
+ if(!stabs&&f)
+ dwarf2_cleanup(f);
+ if(f) section=-1;
+}
diff --git a/machines/alpha/machine.dt b/machines/alpha/machine.dt
new file mode 100755
index 0000000..60cf0b9
--- /dev/null
+++ b/machines/alpha/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S64BULE S64BUBE
+
+
diff --git a/machines/alpha/machine.h b/machines/alpha/machine.h
new file mode 100755
index 0000000..aa05ba8
--- /dev/null
+++ b/machines/alpha/machine.h
@@ -0,0 +1,70 @@
+/* Example of a code-generator for a DEC Alpha */
+
+#include "dt.h"
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Not used in this code-generrator. */
+struct AddressingMode{
+ int flags;
+ int base;
+ int align;
+ long offset;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR 64
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 10
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P LONG
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 0
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 1
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 1
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+/* Parameters are sometimes passed in registers without __reg. */
+#define HAVE_REGPARMS 1
+
+/* Parameters on the stack should be pushed in order rather than */
+/* in reverse order. */
+#define ORDERED_PUSH 1
+
+/* Structure for reg_parm(). */
+struct reg_handle{
+ int nextr;
+};
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/* We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
diff --git a/machines/alpha/schedule.c b/machines/alpha/schedule.c
new file mode 100755
index 0000000..e19e13b
--- /dev/null
+++ b/machines/alpha/schedule.c
@@ -0,0 +1,106 @@
+#include "vsc.h"
+
+char tg_copyright[]="Alpha scheduler V0.0 (c) in 1997 by Volker Barthelmann";
+
+int sched_init(void)
+{
+ return 1;
+}
+void sched_cleanup(void)
+{
+}
+int sched_info(struct sinfo *p)
+{
+ char buf[20];int q1,q2,z,i;
+ if(sscanf(p->txt,"$C%d:",&i)==1){
+ p->label=i;
+ p->flags=LABEL;
+ return 1;
+ }
+ /* lda $r1,imm($r2) */
+ if(sscanf(p->txt,"lda $%d,%d($%d)",&z,&i,&q1)==3){
+ p->latency=1;
+ BSET(p->pipes,0);
+ BSET(p->pipes,1);
+ BSET(p->uses,q1);
+ BSET(p->modifies,z);
+ return 1;
+ }
+ /* lda $r1,... */
+ if(sscanf(p->txt,"lda $%d,",&z)==1){
+ BSET(p->pipes,0);
+ BSET(p->pipes,1);
+ BSET(p->modifies,z);
+ return 1;
+ }
+ /* op $r1,$r2,$r3 */
+ if(sscanf(p->txt,"%19s $%d,$%d,$%d",buf,&q1,&q2,&z)==4){
+ p->latency=1;
+ BSET(p->pipes,0);
+ BSET(p->pipes,1);
+ BSET(p->uses,q1);
+ BSET(p->uses,q2);
+ BSET(p->modifies,z);
+ return 1;
+ }
+ /* op $r1,$r2 */
+ if(sscanf(p->txt,"%19s $%d,$%d",buf,&q1,&z)==3){
+ p->latency=1;
+ BSET(p->pipes,0);
+ BSET(p->pipes,1);
+ BSET(p->uses,q1);
+ BSET(p->modifies,z);
+ return 1;
+ }
+ /* op $r1,imm,$r2 */
+ if(sscanf(p->txt,"%19s $%d,%d,$%d",buf,&q1,&i,&z)==4){
+ p->latency=1;
+ BSET(p->pipes,0);
+ BSET(p->pipes,1);
+ BSET(p->uses,q1);
+ BSET(p->modifies,z);
+ return 1;
+ }
+ /* op $fr1,$fr2,$fr3 */
+ if(sscanf(p->txt,"%19s $f%d,$f%d,$f%d",buf,&q1,&q2,&z)==4){
+ p->latency=1;
+ BSET(p->pipes,2);
+ BSET(p->pipes,3);
+ BSET(p->uses,q1+32);
+ BSET(p->uses,q2+32);
+ BSET(p->modifies,z+32);
+ return 1;
+ }
+ /* load/store $r1,c($r2) */
+ if(sscanf(p->txt,"%19s $%d,%d($%d)",buf,&z,&i,&q1)==4){
+ p->latency=3;
+ BSET(p->pipes,0);
+ BSET(p->uses,q1);
+ if(*buf=='l'){
+ BSET(p->pipes,1);
+ BSET(p->modifies,z);
+ BSET(p->uses,MEM);
+ }else{
+ BSET(p->uses,z);
+ BSET(p->modifies,MEM);
+ }
+ return 1;
+ }
+ /* load/store $fr1,c($r2) */
+ if(sscanf(p->txt,"%19s $f%d,%d($%d)",buf,&z,&i,&q1)==4){
+ p->latency=3;
+ BSET(p->pipes,0);
+ BSET(p->uses,q1);
+ if(*buf=='l'){
+ BSET(p->pipes,1);
+ BSET(p->modifies,z+32);
+ BSET(p->uses,MEM);
+ }else{
+ BSET(p->uses,z+32);
+ BSET(p->modifies,MEM);
+ }
+ return 1;
+ }
+ p->flags=BARRIER;
+ return 1;
+}
diff --git a/machines/alpha/schedule.h b/machines/alpha/schedule.h
new file mode 100755
index 0000000..8603727
--- /dev/null
+++ b/machines/alpha/schedule.h
@@ -0,0 +1,4 @@
+
+#define PIPES 4
+#define REGS 64
+
diff --git a/machines/arm/machine.c b/machines/arm/machine.c
new file mode 100755
index 0000000..1462bef
--- /dev/null
+++ b/machines/arm/machine.c
@@ -0,0 +1,2460 @@
+/*
+ * ARM code generator
+ * A 32-bit RISC with 16 general purpose registers.
+ * Written by Frank Wille <frank@phoenix.owl.de>
+ */
+
+#include "supp.h"
+#include "vbc.h"
+
+static char FILE_[] = __FILE__;
+
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[] = "vbcc code-generator for ARM V0.0 (c) in 2006 by Frank Wille";
+
+/* Commandline-flags the code-generator accepts:
+ 0: just a flag
+ VALFLAG: a value must be specified
+ STRINGFLAG: a string can be specified
+ FUNCFLAG: a function will be called
+ apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF] = {
+ STRINGFLAG,STRINGFLAG,0,0,0,0,
+ 0,0,0,0
+};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+ they collide with the frontend */
+char *g_flags_name[MAXGF] = {
+ "cpu","fpu","little-endian","big-endian","arm","thumb",
+ "const-in-data","merge-constants","elf","use-commons"
+};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. */
+char *regnames[MAXR+1] = {
+ "noreg",
+ "r0","r1","r2","r3","r4","r5","r6","r7",
+ "r8","r9","r10","r11","r12","sp","lr","pc",
+ "s0","s1","s2","s3","s4","s5","s6","s7",
+ "s8","s9","s10","s11","s12","s13","s14","s15",
+ "cpsr",
+ "r0/r1","r2/r3","r4/r5","r6/r7","r10/r11",
+ "d0","d1","d2","d3","d4","d5","d6","d7"
+};
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1] = {
+ 0,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0, /* r0-r3,r12 */
+ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* vfp s0-s3 */
+ 1, /* cpsr */
+ 1,1,0,0,0, /* r0/r1, r2/r3 */
+ 1,1,0,0,0,0,0,0 /* vfp d0-d1 */
+};
+
+/* specifies the priority for the register-allocator, if the same
+ estimated cost-saving can be obtained by several registers, the
+ one with the highest priority will be used */
+int reg_prio[MAXR+1] = {
+ 0,10,11,12,13,2,3,4,5,6,7,8,9,14,0,1,0,
+ 1,2,3,4,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,
+ 10,12,2,4,8,
+ 1,2,0,0,0,0,0,0
+};
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle = {0,0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[] = {
+ "__arm","__thumb","__interrupt","__syscall",0
+};
+#define ARM 1
+#define THUMB 2
+#define INTERRUPT 4
+#define SYSCALL 8
+
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+#define LE_MODE (g_flags[2]&USEDFLAG)
+#define BE_MODE (g_flags[3]&USEDFLAG)
+#define ARM_DEFAULT (g_flags[4]&USEDFLAG)
+#define THUMB_DEFAULT (g_flags[5]&USEDFLAG)
+#define CONST_IN_DATA (g_flags[6]&USEDFLAG)
+#define ELF_LABELS (g_flags[8]&USEDFLAG)
+#define USE_COMMONS (g_flags[9]&USEDFLAG)
+
+int arm_le_mode = 1; /* defaults to little-endian */
+static int thumb_default = 0; /* we start in ARM mode */
+static int thumb = 0; /* current mode */
+
+enum {
+ AAANY=0,AA2,AA3,AA3M,AA4,AA4T,AA5,AA5T,AA5TE
+};
+static int aa = AAANY; /* ARM architecture version */
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1] = {
+ 1,1,2,4,4,8,4,8,8,1,4,1,1,1,4,1
+};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1] = {
+ 1,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0
+};
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp = {LONG};
+static struct Typ lltyp = {LLONG};
+static struct Typ ftyp = {FLOAT};
+static struct Typ dtyp = {DOUBLE};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x,y)=__vattr(\"section(\"#x\",\"#y\")\")",
+ "__ARM__",
+ 0};
+
+/* special registers */
+static int ip = FIRST_GPR+12; /* inter-procedural scratch register */
+static int sp = FIRST_GPR+13; /* stack pointer */
+static int lr = FIRST_GPR+14; /* link register */
+static int pc = FIRST_GPR+15; /* program counter */
+static int r0 = FIRST_GPR;
+static int r1 = FIRST_GPR+1;
+
+/* load/store instructions */
+static char *ldts[MAX_TYPE+1] = {
+ "ldr","ldrsb","ldrsh","ldr","ldr","ldr","ldr","ldr","ldr","??","ldr"};
+static char *ldtu[MAX_TYPE+1] = {
+ "ldr","ldrb","ldrh","ldr","ldr","ldr","??","??","??","??","??"};
+static char *sdts[MAX_TYPE+1] = {
+ "str","strb","strh","str","str","str","str","str","str","??","str"};
+static char *sdtu[MAX_TYPE+1] = {
+ "str","strb","strh","str","str","str","??","??","??","??","??"};
+#define ldt(t) ((t&UNSIGNED) ? ldtu[(t)&NQ] : ldts[(t)&NQ])
+#define sdt(t) ((t&UNSIGNED) ? sdtu[(t)&NQ] : sdts[(t)&NQ])
+
+static char *ldstprefix[] = {
+ "ld","st"
+};
+
+static char *dct[] = {
+ "","byte","short","word","word","word","word","word","word"
+};
+
+static char *ccs[] = {
+ "eq","ne","lt","ge","le","gt",""
+};
+
+static char *logicals[] = {
+ "orr","eor","and"
+};
+
+static char *shifts[2][2] = {
+ "lsl","asr","lsl","lsr"
+};
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+#if 0
+static long stack;
+static int stack_valid;
+#endif
+static int newobj;
+static int section = -1;
+
+static char *codename = "\t.text\n";
+static char *dataname = "\t.data\n";
+static char *bssname = "";
+static char *rodataname = "\t.rodata\n";
+
+/* list of floating point constants to output at end of file */
+struct fpconstlist {
+ struct fpconstlist *next;
+ int label;
+ int typ;
+ union atyps val;
+};
+static struct fpconstlist *firstfpc = NULL;
+
+/* data reference pointers at the end of each function */
+struct DataRefPtrList {
+ struct DataRefPtrList *next;
+ int label;
+ struct Var *vptr; /* valid, when label==0 */
+};
+static struct DataRefPtrList *dataptrs = NULL;
+static int drefptr_array_label; /* current array's label */
+
+#define isreg(x) (((x)&(REG|DREFOBJ))==REG)
+#define isconst(x) (((x)&(KONST|DREFOBJ))==KONST)
+
+static int q1reg,q2reg,zreg;
+static struct Var *current_function;
+static int icnt; /* counts number of lines in cur. function */
+
+#define MAXCODELINES 500 /* emit data-ref. ptr array after that */
+#define MAXCOPYINSTS 4 /* max. nb. of load/store copy-instructions */
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l";
+static char *idprefix="_";
+
+/* variables to calculate the size and partitioning of the stack-frame */
+static long frameoffset,pushoffs,framesize;
+static int needframe;
+static long localsize,rsavesize,argsize,rsaveoffs,maxrsaveoffs;
+
+
+
+static long real_offset(struct obj *o)
+/* calculate the actual current offset of an object relative to the
+ stack-pointer; we use a layout like this:
+ ------------------------------------------------
+ | stack-arguments to this function |
+ ------------------------------------------------
+ | caller-save registers [size=rsavesize] |
+ ------------------------------------------------
+ | local variables [size=localsize] |
+ ------------------------------------------------
+ | arguments to called functions [size=argsize] |
+ ------------------------------------------------
+ All sizes will be aligned as necessary.
+ The stack-pointer will be adjusted at
+ function-entry to leave enough space for the arguments and have it
+ aligned to 16 bytes. Therefore, when calling a function, the
+ stack-pointer is always aligned to 16 bytes.
+*/
+{
+ long off = zm2l(o->v->offset);
+
+ if (off < 0) {
+ /* function parameter */
+ off = localsize + rsavesize - off - zm2l(maxalign);
+ }
+ else {
+ /* local variable */
+ off += argsize;
+ off += zm2l(o->val.vmax);
+ }
+
+ return off;
+}
+
+
+static struct obj *cam(int flags,int base,long offset)
+/* Initializes an addressing-mode structure and returns a pointer to
+ that object. Will not survive a second call! */
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+
+#if 0
+ obj.am = &am;
+ am.flags = flags;
+ am.base = base;
+ am.offset = offset;
+#endif
+ return &obj;
+}
+
+
+static int objalign(struct obj *o)
+/* yields the object's lower two bits, 1 when unknown */
+{
+ if (o->flags & DREFOBJ)
+ return 1;
+ if (o->am)
+ ierror(0);
+ if (!(o->flags & VAR))
+ ierror(0);
+
+ if (isstatic(o->v->storage_class) || isextern(o->v->storage_class)) {
+ /* all static data should be 32-bits aligned */
+ return zm2l(zmand(o->val.vmax,l2zm(3L)));
+ }
+
+ if (isauto(o->v->storage_class)) {
+ zmax of = o->v->offset;
+
+ if (!zmleq(l2zm(0L),of))
+ of = zmsub(l2zm(0L),zmadd(of,maxalign));
+ return zm2l(zmand(zmadd(of,o->val.vmax),l2zm(3L)));
+ }
+
+ ierror(0);
+}
+
+
+static void title(FILE *f)
+/* set file symbol with input file name */
+{
+ extern char *inname;
+ static int done;
+
+ if (!done && f) {
+ done = 1;
+ emit(f,"\t.file\t\"%s\"\n",inname);
+ }
+}
+
+
+static void emitnl(FILE *f)
+/* emit a newline character */
+{
+ emit(f,"\n");
+}
+
+
+static void emit_obj(FILE *f,struct obj *p,int t)
+/* prints an object */
+{
+ if (p->flags & VAR) {
+ if (isauto(p->v->storage_class)) {
+ emit(f,"[%s,#%ld]",regnames[sp],real_offset(p));
+ }
+ else {
+ if (!zmeqto(l2zm(0L),p->val.vmax)) {
+ emitval(f,&p->val,LONG);
+ emit(f,"+");
+ }
+ if (isstatic(p->v->storage_class))
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ else
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ }
+
+ if (p->flags & REG) {
+ emit(f,"%s",regnames[p->reg]);
+ }
+
+ if (p->flags & KONST) {
+ emit(f,"#");
+ emitval(f,&p->val,t&NU);
+ }
+}
+
+
+static int special_section(FILE *f,struct Var *v)
+/* changes to a special section, used for __section() */
+{
+ char *sec;
+
+ if (v->vattr) {
+ if (sec = strstr(v->vattr,"section(")) {
+ sec += strlen("section(");
+ emit(f,"\t.section\t");
+ while (*sec && *sec!=')')
+ emit_char(f,*sec++);
+ emitnl(f);
+ if (f)
+ section = SPECIAL;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static int addfpconst(struct obj *o,int t)
+/* return label for a float-constant, create if it didn't exist */
+{
+ struct fpconstlist *p=firstfpc;
+
+ t &= NQ;
+ if (t == LDOUBLE)
+ t = DOUBLE;
+
+ for (p=firstfpc; p; p=p->next) {
+ if (t == p->typ) {
+ eval_const(&p->val,t);
+ if (t==FLOAT && zldeqto(vldouble,zf2zld(o->val.vfloat)))
+ return p->label;
+ if (t==DOUBLE && zldeqto(vldouble,zd2zld(o->val.vdouble)))
+ return p->label;
+ }
+ }
+
+ p = mymalloc(sizeof(struct fpconstlist));
+ p->next = firstfpc;
+ p->label = ++label;
+ p->typ = t;
+ p->val = o->val;
+ firstfpc = p;
+
+ return p->label;
+}
+
+
+static void emit_dataptr_array(FILE *f)
+/* emit all data-reference pointers which were collected until now,
+ then reset the array */
+{
+ struct DataRefPtrList *drp,*next;
+
+ if (next = dataptrs) {
+ emit(f,"\t.align\t2\n");
+ emit(f,"%s%d:\n",labprefix,drefptr_array_label);
+
+ while (drp = next) {
+ next = drp->next;
+ emit(f,"\t.%s\t",dct[LONG]);
+ if (drp->label) {
+ emit(f,"%s%d\n",labprefix,drp->label);
+ }
+ else {
+ if (isstatic(drp->vptr->storage_class))
+ emit(f,"%s%ld\n",labprefix,zm2l(drp->vptr->offset));
+ else
+ emit(f,"%s%s\n",idprefix,drp->vptr->identifier);
+ }
+ free(drp);
+ }
+ dataptrs = NULL;
+ }
+ drefptr_array_label = 0;
+}
+
+
+static int cg_getreg(FILE *f,struct IC *ic)
+/* allocate a code generator internal general purpose register */
+{
+ /* alloc_code: 1:compiler, 2:backend, >=4:backend rsave-area offset - 4 */
+ int alloc_code = 2;
+ int i,p,r;
+
+ /* try to get a free scratch-register or a non-volatile
+ register which has to be saved anyway,
+ r12 (ip) is reserved to the backend and will be used as well,
+ r14 (lr) is available when the function builds a stack frame */
+ for (i=FIRST_GPR,p=0,r=0; i<FIRST_GPR+13; i++) {
+ if (((i==ip && regs[i]==1) ||
+ (i==lr && regs[i]==1 && needframe) ||
+ (regs[i]==0 && (regscratch[i] || regused[i]))) &&
+ reg_prio[i]+(regused[i]<<8) > p) {
+ p = reg_prio[i] + (regused[i] << 8);
+ r = i;
+ }
+ }
+ if (!r) {
+ /* seems we have to save a new non-volatile register */
+ for (i=FIRST_GPR,p=0; i<FIRST_GPR+13; i++) {
+ if (regs[i]==0 && reg_prio[i]>p) {
+ p = reg_prio[i];
+ r = i;
+ }
+ }
+ }
+ if (!r) {
+ /* no register available - save one to the stack-frame, but
+ make sure it is not used in this IC */
+ for (i=FIRST_GPR,p=0; i<FIRST_GPR+13; i++) {
+ if (regs[i]<2 && reg_prio[i]>p) {
+ if ((!isreg(ic->q1.flags) || ic->q1.reg!=i) &&
+ (!isreg(ic->q2.flags) || ic->q2.reg!=i) &&
+ (!isreg(ic->z.flags) || ic->z.reg!=i)) {
+ p = reg_prio[i];
+ r = i;
+ }
+ }
+ }
+ if (r) {
+ if (f)
+ emit(f,"\tstr\t%s,[%s,#%ld]\n",
+ regnames[r],regnames[sp],argsize+localsize+rsaveoffs);
+ rsaveoffs += 4;
+ if (rsaveoffs > maxrsaveoffs)
+ maxrsaveoffs = rsaveoffs;
+ alloc_code = rsaveoffs;
+ }
+ else
+ ierror(0);
+ }
+
+ regs[r] = alloc_code;
+ regused[r] = 1;
+ return r;
+}
+
+
+static int cg_getdpreg(FILE *f,struct IC *ic)
+/* allocate a code generator internal double precision FP register */
+{
+ int i,p,r;
+ struct rpair rp;
+
+ /* try to get a free scratch-register or a non-volatile
+ register which has to be saved anyway */
+ for (i=FIRST_DOUBLE,p=0,r=0; i<=LAST_PAIR; i++) {
+ if (regs[i]==0 && (regscratch[i] || regused[i]) &&
+ reg_prio[i]+(regused[i]<<8) > p && reg_pair(i,&rp)) {
+ if (regs[rp.r1]==0 && regs[rp.r2]==0) {
+ p = reg_prio[i] + (regused[i] << 8);
+ r = i;
+ }
+ }
+ }
+ if (!r) {
+ ierror(0); /* @@@ FIXME */
+ }
+
+ regs[r] = 2;
+ regused[r] = 1;
+ if (!reg_pair(i,&rp))
+ ierror(0);
+ regs[rp.r1] = regs[rp.r2] = 2;
+ regused[rp.r1] = regused[rp.r2] = 1;
+ return r;
+}
+
+
+static void cg_restorereg(FILE *f,int r)
+{
+ if (f) {
+ if (r <= LAST_GPR)
+ emit(f,"\tldr\t%s,[%s,#%ld]\n",
+ regnames[r],regnames[sp],argsize+localsize+regs[r]-4);
+ else
+ ierror(0); /* @@@ FIXME */
+ }
+}
+
+
+static void cg_freereg(FILE *f,int r)
+/* free a code generator internal general purpose register */
+{
+ struct rpair rp;
+
+ if (regs[r] > 1) {
+ if (regs[r] > 2)
+ cg_restorereg(f,r);
+ regs[r] = (r==ip||r==lr) ? 1 : 0; /* ip/lr need to stay reserved */
+ }
+ else
+ ierror(0);
+
+ if (reg_pair(r,&rp)) {
+ if (regs[rp.r1]>1 && regs[rp.r2]>1) {
+ if (regs[rp.r1] > 2)
+ cg_restorereg(f,rp.r1);
+ if (regs[rp.r2] > 2)
+ cg_restorereg(f,rp.r2);
+ regs[rp.r1] = regs[rp.r2] = 0;
+ }
+ else
+ ierror(0);
+ }
+}
+
+
+static void cg_freeall(FILE *f)
+/* reset internal register allocations */
+{
+ int i;
+
+ for (i=1; i<=MAXR; i++) {
+ if (regs[i] > 1) {
+ if (regs[i] > 2)
+ cg_restorereg(f,i);
+ regs[i] = (i==ip||i==lr) ? 1 : 0; /* ip/lr need to stay reserved */
+ }
+ }
+ rsaveoffs = 0;
+}
+
+
+static long dataptr_offset(int label,struct obj *o)
+/* return offset into data-reference-pointer array for label l
+ or for object o (mutually exclusive) */
+{
+ long off = 0;
+ struct DataRefPtrList **olddrp = &dataptrs;
+ struct DataRefPtrList *drp = dataptrs;
+
+ if (!label) {
+ if (!(o->flags & VAR))
+ ierror(0);
+ if (!isstatic(o->v->storage_class) && !isextern(o->v->storage_class))
+ ierror(0);
+ }
+
+ /* check if a pointer to this object already exists */
+ while (drp) {
+ if (label) {
+ if (drp->label == label)
+ break;
+ }
+ else {
+ if (drp->vptr == o->v)
+ break;
+ }
+ olddrp = &drp->next;
+ drp = drp->next;
+ off += 4;
+ }
+
+ /* create a new entry if it doesn't exist */
+ if (drp == NULL) {
+ *olddrp = drp = mymalloc(sizeof(struct DataRefPtrList));
+
+ drp->next = NULL;
+ if (drp->label = label)
+ drp->vptr = NULL;
+ else
+ drp->vptr = o->v;
+ }
+
+ return off;
+}
+
+
+static void load_dataptr(FILE *f,int r,int l,struct obj *o)
+/* load data-reference-pointer array entry for label l or object o into r */
+{
+ BSET(regs_modified,r);
+
+ if (!drefptr_array_label)
+ drefptr_array_label = ++label;
+
+ emit(f,"\tldr\t%s,%s%d+%ld\n",
+ regnames[r],labprefix,drefptr_array_label,dataptr_offset(l,o));
+}
+
+
+static void ldst64(FILE *f,int store,struct rpair *rp,int base)
+/* generate a ldmia or stmia (store=1) instruction to transfer a 64-bit
+ value in register pair rp pointed to by base-register base */
+{
+ emit(f,"%smia\t%s,{%s-%s}\n",
+ ldstprefix[store],regnames[base],regnames[rp->r1],regnames[rp->r2]);
+}
+
+
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/* Generates code to load the address of a variable into register r. */
+{
+ BSET(regs_modified,r);
+
+ if (!(o->flags & VAR))
+ ierror(0);
+
+ if (isauto(o->v->storage_class))
+ emit(f,"\tadd\t%s,%s,#%ld\n",regnames[r],regnames[sp],real_offset(o));
+ else
+ load_dataptr(f,r,0,o);
+}
+
+
+static void load_regindir(FILE *f,struct IC *p,int type,
+ int dst,int base,long off)
+/* Load register dst of type type from [base,#off].
+ base and dst may be the same.
+ Perform size extensions as required by architecture. */
+{
+ BSET(regs_modified,dst);
+
+ if (aa >= AA4) {
+ emit(f,"\t%s\t%s,[%s,#%ld]\n",
+ ldt(type),regnames[dst],regnames[base],off);
+ }
+
+ else {
+ /* this requires more effort on older ARMs */
+ int tmp;
+
+ switch (sizetab[type&NQ]) {
+ case 1:
+ emit(f,"\tldrb\t%s,[%s,#%ld]\n",regnames[dst],regnames[base],off);
+ if (!(type & UNSIGNED)) {
+ emit(f,"\tmov\t%s,%s,lsl #24\n",regnames[dst],regnames[dst]);
+ emit(f,"\tmov\t%s,%s,asr #24\n",regnames[dst],regnames[dst]);
+ }
+ break;
+ case 2:
+ tmp = cg_getreg(f,p);
+ emit(f,"\tldrb\t%s,[%s,#%ld]\n",regnames[tmp],regnames[base],
+ off+1-arm_le_mode);
+ emit(f,"\tldrb\t%s,[%s,#%ld]\n",regnames[dst],regnames[base],
+ off+arm_le_mode);
+ if (!(type & UNSIGNED)) {
+ emit(f,"\tmov\t%s,%s,lsl #24\n",regnames[dst],regnames[dst]);
+ emit(f,"\torr\t%s,%s,%s asr #16\n",
+ regnames[dst],regnames[tmp],regnames[dst]);
+ }
+ else {
+ emit(f,"\torr\t%s,%s,%s lsl #8\n",
+ regnames[dst],regnames[tmp],regnames[dst]);
+ }
+ cg_freereg(f,tmp);
+ break;
+ case 4:
+ emit(f,"\tldr\t%s,[%s,#%ld]\n",regnames[dst],regnames[base],off);
+ break;
+ default:
+ ierror(0);
+ }
+ }
+}
+
+
+static void load_reg(FILE *f,struct IC *p,int r,struct obj *o,int type)
+/* Generates code to load a memory object into register r. */
+{
+ type &= NU;
+ BSET(regs_modified,r);
+
+ if (o->flags & KONST) {
+ /* evaluate and load a constant */
+
+ eval_const(&o->val,type);
+
+ if (ISFLOAT(type)) {
+ int lab = addfpconst(o,type);
+
+ load_dataptr(f,r,lab,NULL);
+ if (type == FLOAT)
+ load_regindir(f,p,type,r,r,0);
+ else
+ ierror(0); /* double can only be in a register-pair */
+ }
+
+ else {
+ /* integer constant */
+ emit(f,"\tmov\t%s,",regnames[r]);
+ emit_obj(f,o,type);
+ emitnl(f);
+ }
+ }
+
+ else if (isreg(o->flags)) {
+ if (r != o->reg)
+ emit(f,"\tmov\t%s,%s\n",regnames[r],regnames[o->reg]);
+ }
+
+ else if ((o->flags & (REG|DREFOBJ)) == (REG|DREFOBJ)) {
+ load_regindir(f,p,type,r,o->reg,0);
+ }
+
+ else if (o->flags & VAR) {
+ if (isstatic(o->v->storage_class) || isextern(o->v->storage_class)) {
+ /* load from a static variable */
+ if (o->flags & VARADR) {
+ load_address(f,r,o,POINTER);
+ }
+ else {
+ load_dataptr(f,r,0,o);
+ load_regindir(f,p,type,r,r,zm2l(o->val.vmax));
+ }
+ }
+ else {
+ /* dynamic variable on stack */
+ load_regindir(f,p,type,r,sp,real_offset(o));
+ }
+ }
+
+ else
+ ierror(0);
+}
+
+
+static void store_regindir(FILE *f,struct IC *p,int type,
+ int src,int base,long off)
+/* Store register src of type type to [base,#off]. */
+{
+ if (aa>=AA4 || sizetab[type&NQ]!=2) {
+ emit(f,"\t%s\t%s,[%s,#%ld]\n",
+ sdt(type),regnames[src],regnames[base],off);
+ }
+
+ else {
+ /* storing halfwords requires more effort on older ARMs */
+ int tmp = cg_getreg(f,p);
+
+ emit(f,"\tstrb\t%s,[%s,#%ld]\n",regnames[src],regnames[base],
+ off+1-arm_le_mode);
+ emit(f,"\tmov\t%s,%s,asr #8\n",regnames[tmp],regnames[src]);
+ emit(f,"\tstrb\t%s,[%s,#%ld]\n",regnames[src],regnames[base],
+ off+arm_le_mode);
+ cg_freereg(f,tmp);
+ }
+}
+
+
+static void store_reg(FILE *f,struct IC *p,int r,struct obj *o,int type)
+/* Generates code to store register r into memory object o. */
+{
+ if (isreg(o->flags)) {
+ if (r != o->reg)
+ emit(f,"\tmov\t%s,%s\n",regnames[o->reg],regnames[r]);
+ }
+
+ else if ((o->flags & (REG|DREFOBJ)) == (REG|DREFOBJ)) {
+ store_regindir(f,p,type,r,o->reg,0);
+ }
+
+ else if (o->flags & VAR) {
+ if (isstatic(o->v->storage_class) || isextern(o->v->storage_class)) {
+ /* store to a static variable */
+ int tmp = cg_getreg(f,p);
+
+ load_dataptr(f,tmp,0,o);
+ store_regindir(f,p,type,r,tmp,zm2l(o->val.vmax));
+ cg_freereg(f,tmp);
+ }
+ else {
+ /* dynamic variable on stack */
+ store_regindir(f,p,type,r,sp,real_offset(o));
+ }
+ }
+
+ else
+ ierror(0);
+}
+
+
+static int load_objptr(FILE *f,struct IC *p,struct obj *o)
+/* Make sure object o can be dereferenced by a single load.
+ Return new base register, or 0 if object was not modified. */
+{
+ if ((o->flags & (REG|DREFOBJ)) == DREFOBJ) {
+ int r = cg_getreg(f,p);
+
+ load_reg(f,p,r,o,POINTER);
+ o->flags |= REG;
+ o->reg = r;
+ return r;
+ }
+
+ if ((o->flags & (VAR|REG)) == VAR) {
+ if (isstatic(o->v->storage_class) || isextern(o->v->storage_class)) {
+ int r = cg_getreg(f,p);
+
+ load_dataptr(f,r,0,o);
+ o->reg = r;
+ o->flags = REG|DREFOBJ;
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+
+static void load_regpair(FILE *f,struct IC *p,struct rpair *rp,
+ struct obj *o,int type)
+/* Generates code to load a memory object into the register pair rp.
+ tmp is a general purpose register which may be used. */
+{
+ BSET(regs_modified,rp->r1);
+ BSET(regs_modified,rp->r2);
+
+ if (o->flags & KONST) {
+ /* evaluate and load a constant */
+ eval_const(&o->val,type);
+
+ if (ISFLOAT(type)) {
+ int lab = addfpconst(o,type);
+ int tmp = cg_getreg(f,p);
+
+ load_dataptr(f,tmp,lab,NULL);
+ if (type != FLOAT)
+ ldst64(f,0,rp,tmp);
+ else
+ ierror(0); /* have to load float in a single register */
+ cg_freereg(f,tmp);
+ }
+ else {
+ struct obj cobj;
+
+ cobj.flags = KONST;
+ cobj.val.vulong = zum2zul(zumand(vumax,ul2zum(0xffffffff)));
+ load_reg(f,p,arm_le_mode?rp->r1:rp->r2,&cobj,UNSIGNED|LONG);
+ cobj.val.vulong = zum2zul(zumand(zumrshift(vumax,ul2zum(32UL)),
+ ul2zum(0xffffffff)));
+ load_reg(f,p,arm_le_mode?rp->r2:rp->r1,&cobj,UNSIGNED|LONG);
+ }
+ }
+
+ else {
+ /* make sure that object can be addressed through a register */
+ load_objptr(f,p,o);
+
+ if (isreg(o->flags)) {
+ struct rpair qrp;
+
+ if (!reg_pair(o->reg,&qrp))
+ ierror(0);
+ if (qrp.r1 != rp->r1) {
+ emit(f,"\tmov\t%s,%s\n\tmov\t%s,%s\n",regnames[rp->r1],
+ regnames[qrp.r1],regnames[rp->r2],regnames[qrp.r2]);
+ }
+ }
+ else if ((o->flags & (REG|DREFOBJ)) == (REG|DREFOBJ)) {
+ ldst64(f,0,rp,o->reg);
+ }
+ else
+ ierror(0);
+ }
+}
+
+
+static void store_regpair(FILE *f,struct IC *p,struct rpair *rp,
+ struct obj *o,int type)
+/* Generates code to store the register pair rp into memory object o.
+ tmp is a general purpose register which may be used. */
+{
+ /* make sure that object can be addressed through a register */
+ load_objptr(f,p,o);
+
+ if (isreg(o->flags)) {
+ struct rpair zrp;
+
+ if (!reg_pair(o->reg,&zrp))
+ ierror(0);
+ if (zrp.r1 != rp->r1) {
+ emit(f,"\tmov\t%s,%s\n\tmov\t%s,%s\n",regnames[zrp.r1],
+ regnames[rp->r1],regnames[zrp.r2],regnames[rp->r2]);
+ }
+ }
+ else if ((o->flags & (REG|DREFOBJ)) == (REG|DREFOBJ)) {
+ ldst64(f,1,rp,o->reg);
+ }
+ else
+ ierror(0);
+}
+
+
+static long pof2(zumax x)
+/* yields log2(x)+1 or 0 */
+{
+ zumax p;
+ int ln = 1;
+
+ p = ul2zum(1L);
+ while (ln<=32 && zumleq(p,x)) {
+ if (zumeqto(x,p))
+ return ln;
+ ln++;
+ p = zumadd(p,p);
+ }
+ return 0;
+}
+
+
+static struct IC *preload(FILE *f,struct IC *p)
+/* Does some pre-processing like fetching operands from memory to
+ registers etc. */
+/* @@@ FIXME - Is this function needed at all ??? */
+{
+#if 0
+ if (isreg(p->q1.flags))
+ q1reg = p->q1.reg;
+ else
+ q1reg = 0;
+
+ if (isreg(p->q2.flags))
+ q2reg = p->q2.reg;
+ else
+ q2reg = 0;
+#endif
+
+ if (isreg(p->z.flags)) {
+ zreg = p->z.reg;
+ }
+ else {
+ if (ISFLOAT(ztyp(p)))
+ zreg = FIRST_PAIR; /* @@@ VFP? ->f1 */
+ else
+ zreg = cg_getreg(f,p);
+ }
+
+#if 0 /* Better use load_objptr() when needed? */
+ if ((p->q1.flags & (REG|DREFOBJ)) == DREFOBJ) {
+ int tmp = cg_getreg(f,p);
+
+ p->q1.flags &= ~DREFOBJ;
+ load_reg(f,p,tmp,&p->q1,q1typ(p));
+ p->q1.reg = tmp;
+ p->q1.flags |= REG|DREFOBJ;
+ }
+
+ if ((p->q2.flags & (REG|DREFOBJ)) == DREFOBJ) {
+ int tmp = cg_getreg(f,p);
+
+ p->q2.flags &= ~DREFOBJ;
+ load_reg(f,p,tmp,&p->q2,q2typ(p));
+ p->q2.reg = tmp;
+ p->q2.flags |= REG|DREFOBJ;
+ }
+#endif
+
+ return p;
+}
+
+
+static void save_result(FILE *f,struct IC *p)
+/* save the result (in zreg) into p->z */
+{
+ if ((p->z.flags&(REG|DREFOBJ)) == DREFOBJ) {
+ int tmp = cg_getreg(f,p);
+
+ p->z.flags &= ~DREFOBJ;
+ load_reg(f,p,tmp,&p->z,POINTER);
+ p->z.reg = tmp;
+ p->z.flags |= REG|DREFOBJ;
+ }
+ if (isreg(p->z.flags)) {
+ if (p->z.reg != zreg)
+ emit(f,"\tmov\t%s,%s\n",regnames[p->z.reg],regnames[zreg]);
+ }
+ else {
+ store_reg(f,p,zreg,&p->z,ztyp(p));
+ }
+}
+
+
+static void registerize(FILE *f,struct IC *p,struct obj *o,int t)
+/* make sure object is loaded into a register */
+{
+ if (!(isreg(o->flags))) {
+ int r;
+
+ r = load_objptr(f,p,o);
+ if (!r)
+ r = cg_getreg(f,p);
+ if ((o->flags & (REG|DREFOBJ)) == DREFOBJ)
+ ierror(0);
+ load_reg(f,p,r,o,t);
+ o->reg = r;
+ }
+ o->flags = REG;
+}
+
+
+static void cg_memcopy(FILE *f,struct IC *p)
+/* generates code to copy an object of non-elementary type (ARRAY, STRUCT) */
+{
+ unsigned long size = opsize(p);
+ int a1 = objalign(&p->q1);
+ int a2 = (p->code==ASSIGN) ? objalign(&p->z) : 0;
+ int b = 1;
+ char *ld = ldt(CHAR);
+ char *st = sdt(CHAR);
+ unsigned long l;
+ int srcreg,dstreg,tmpreg,cntreg,ncp;
+
+ if (p->q1.flags & VAR) {
+ if (p->q1.flags & DREFOBJ) {
+ if (p->q1.v->vtyp->next &&
+ zmeqto(p->q2.val.vmax,szof(p->q1.v->vtyp->next)) && (a1&1)) {
+ a1 = zm2l(falign(p->q1.v->vtyp->next)) & 3;
+ a2 &= a1;
+ }
+ }
+ else {
+ if (zmeqto(p->q2.val.vmax,szof(p->q1.v->vtyp)) && (a1&1)) {
+ a1 = zm2l(falign(p->q1.v->vtyp)) & 3;
+ a2 &= a1;
+ }
+ }
+ }
+ if (p->z.flags & VAR) {
+ if (p->z.flags & DREFOBJ) {
+ if (p->z.v->vtyp->next &&
+ zmeqto(p->q2.val.vmax,szof(p->z.v->vtyp->next)) && (a2&1)) {
+ a2 = zm2l(falign(p->z.v->vtyp->next)) & 3;
+ a1 &= a2;
+ }
+ }
+ else {
+ if (zmeqto(p->q2.val.vmax,szof(p->z.v->vtyp)) && (a2&1)) {
+ a2 = zm2l(falign(p->z.v->vtyp)) & 3;
+ a1 &= a2;
+ }
+ }
+ }
+
+ /* @@@ implement with ldmia/stmia */
+ if (a1>=0 && a2>=0) {
+ if (a1==0 && a2==0) {
+ /* 32-bit copy */
+ b = 4;
+ ld = ldt(LONG);
+ st = sdt(LONG);
+ }
+ else if ((a1&1)==0 && (a2&1)==0 && aa>=AA4) {
+ /* 16-bit copy for ARM-architecture 4 and better only */
+ b = 2;
+ ld = ldt(SHORT);
+ st = sdt(SHORT);
+ }
+ }
+
+ srcreg = cg_getreg(f,p);
+ BSET(regs_modified,srcreg);
+
+ if (p->q1.flags & DREFOBJ) {
+ p->q1.flags &= ~DREFOBJ;
+ if (isreg(p->q1.flags))
+ emit(f,"\tmov\t%s,%s\n",regnames[srcreg],regnames[p->q1.reg]);
+ else
+ load_reg(f,p,srcreg,&p->q1,POINTER);
+ p->q1.flags |= DREFOBJ;
+ }
+ else {
+ load_address(f,srcreg,&p->q1,POINTER);
+ }
+
+ dstreg = cg_getreg(f,p);
+ BSET(regs_modified,dstreg);
+
+ if (p->z.flags & DREFOBJ) {
+ p->z.flags &= ~DREFOBJ;
+ if (isreg(p->z.flags))
+ emit(f,"\tmov\t%s,%s\n",regnames[dstreg],regnames[p->z.reg]);
+ else
+ load_reg(f,p,dstreg,&p->z,POINTER);
+ p->z.flags |= DREFOBJ;
+ }
+ else {
+ if (p->code == PUSH) {
+ emit(f,"\tadd\t%s,%s,#%ld\n",regnames[dstreg],regnames[sp],pushoffs);
+ pushoffs += size;
+ }
+ else
+ load_address(f,dstreg,&p->z,POINTER);
+ }
+
+ tmpreg = cg_getreg(f,p);
+ BSET(regs_modified,tmpreg);
+ l = size/b;
+
+ if (l > MAXCOPYINSTS) { /* @@@ make MAXCOPYINSTS changeable by an option? */
+ cntreg = cg_getreg(f,p);
+ BSET(regs_modified,cntreg);
+ emit(f,"\tmov\t%s,#%lu\n",regnames[cntreg],l);
+ emit(f,"%s%d:\n",labprefix,++label);
+ ncp = 1;
+ }
+ else
+ ncp = l;
+ while (ncp--) {
+ emit(f,"\t%s\t%s,[%s],#%d\n",ld,regnames[tmpreg],regnames[srcreg],b);
+ emit(f,"\t%s\t%s,[%s],#%d\n",st,regnames[tmpreg],regnames[dstreg],b);
+ }
+ if (l > MAXCOPYINSTS) {
+ emit(f,"\tsubs\t%s,%s,#1\n",regnames[cntreg],regnames[cntreg]);
+ emit(f,"\tbne\t%s%d\n",labprefix,label);
+ cg_freereg(f,cntreg);
+ }
+
+ size = size % b;
+ ncp = 0;
+ if (size & 2) {
+ if (aa >= AA4) {
+ emit(f,"\t%s\t%s,[%s],#%d\n",ldt(SHORT),regnames[tmpreg],regnames[srcreg],b);
+ emit(f,"\t%s\t%s,[%s],#%d\n",sdt(SHORT),regnames[tmpreg],regnames[dstreg],b);
+ }
+ else
+ ncp = 2;
+ }
+ ncp += (size & 1);
+ while (ncp--) {
+ emit(f,"\t%s\t%s,[%s],#%d\n",ldt(CHAR),regnames[tmpreg],regnames[srcreg],b);
+ emit(f,"\t%s\t%s,[%s],#%d\n",sdt(CHAR),regnames[tmpreg],regnames[dstreg],b);
+ }
+}
+
+
+static int exists_freereg(struct IC *p,int reg)
+/* Test if there is a sequence of FREEREGs containing FREEREG reg.
+ Used by peephole(). */
+{
+ while (p && (p->code==FREEREG || p->code==ALLOCREG)) {
+ if (p->code==FREEREG && p->q1.reg==reg)
+ return 1;
+ p=p->next;
+ }
+ return 0;
+}
+
+
+#if 0
+static void peephole(struct IC *p)
+/* search for possible addressing-modes */
+{
+ int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+ for(;p;p=p->next){
+ c=p->code;
+ if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(p->q1.flags)||p->q1.reg!=p->z.reg)) exit_label=0;
+ if(c==LABEL) exit_label=p->typf;
+
+ /* Try const(reg) */
+ if(IMM_IND&&(c==ADDI2P||c==SUBIFP)&&isreg(p->z.flags)&&isconst(p->q2.flags)){
+ int base;zmax of;struct obj *o;
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ if(1/*zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))*/){
+ r=p->z.reg;
+ if(isreg(p->q1.flags)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&isreg(p2->q1.flags)&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&isreg(p2->q2.flags)&&p2->q2.reg==r) break;
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||isreg(p2->z.flags)){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ am->base=base;
+ am->offset=zm2l(of);
+ if(isreg(p->q1.flags)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+ /* Try reg,reg */
+ if(GPR_IND&&c==ADDI2P&&isreg(p->q2.flags)&&isreg(p->z.flags)&&(isreg(p->q1.flags)||p->q2.reg!=p->z.reg)){
+ int base,idx;struct obj *o;
+ r=p->z.reg;idx=p->q2.reg;
+ if(isreg(p->q1.flags)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&isreg(p2->q1.flags)&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&isreg(p2->q2.flags)&&p2->q2.reg==r) break;
+ if(isreg(p2->z.flags)&&p2->z.reg==idx&&idx!=r) break;
+
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||(q1typ(p2)&NQ)==LLONG) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||(q2typ(p2)&NQ)==LLONG) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||(ztyp(p2)&NQ)==LLONG) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||isreg(p2->z.flags)){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=GPR_IND;
+ am->base=base;
+ am->offset=idx;
+ if(isreg(p->q1.flags)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+}
+#endif
+
+
+static void function_top(FILE *f,struct Var *v,long offset)
+/* generates the function entry code */
+{
+ static char ret_instr[64];
+ char gprsave[32];
+ char *p;
+ int i;
+
+ title(f);
+
+ /* determine rsavesize and registers to save */
+ rsavesize = 0;
+ gprsave[0] = '\0';
+ for (i=FIRST_GPR,p=gprsave; i<=LAST_GPR; i++) {
+ if (!regsa[i] && !regscratch[i] && regused[i]) {
+ p += sprintf(p,"%s,",regnames[i]);
+ rsavesize += 4;
+ }
+ }
+
+ if (!special_section(f,v) && section!=CODE) {
+ emit(f,codename);
+ section = CODE;
+ }
+
+ if (isextern(v->storage_class)) {
+ if ((v->flags & (INLINEFUNC|INLINEEXT)) != INLINEFUNC)
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }
+ else
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+
+ if (rsavesize==0 && !needframe) {
+ ret = "\tmov\tpc,lr\n";
+ }
+ else {
+ rsavesize += 3*4; /* sp,lr,pc to be saved as well */
+ emit(f,"\tstmfd\t%s!,{%s%s,%s,%s}\n",
+ regnames[sp],gprsave,regnames[sp],regnames[lr],regnames[pc]);
+ sprintf(ret_instr,"\tldmfd\t%s,{%s%s,%s}\n",
+ regnames[sp],gprsave,regnames[sp],regnames[pc]);
+ ret = ret_instr;
+ if (localsize+argsize > 0) {
+ emit(f,"\tsub\t%s,%s,#%ld\n",
+ regnames[sp],regnames[sp],localsize+argsize);
+ }
+ }
+}
+
+
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/* generates the function exit code */
+{
+ if (localsize+argsize > 0) {
+ emit(f,"\tadd\t%s,%s,#%ld\n",
+ regnames[sp],regnames[sp],localsize+argsize);
+ }
+ emit(f,ret);
+ emit_dataptr_array(f);
+
+ if (isextern(v->storage_class)) {
+ emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+ emit(f,"\t.size\t%s%s,.-%s%s\n\n",
+ idprefix,v->identifier,idprefix,v->identifier);
+ }
+ else {
+ emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset));
+ emit(f,"\t.size\t%s%ld,.-%s%ld\n\n",
+ labprefix,zm2l(v->offset),labprefix,zm2l(v->offset));
+ }
+
+ /*if(all_regs&&v->fi) v->fi->flags|=ALL_REGS;*/
+}
+
+
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+
+int init_cg(void)
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+{
+ int i;
+
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign = l2zm(8L);
+ stackalign = l2zm(4L);
+ char_bit = l2zm(8L);
+
+ for (i=0; i<=MAX_TYPE; i++) {
+ sizetab[i] = l2zm(msizetab[i]);
+ align[i] = l2zm(malign[i]);
+ }
+
+ for (i=FIRST_GPR; i<=LAST_GPR; i++) {
+ regsize[i] = l2zm(4L);
+ regtype[i] = <yp;
+ }
+
+ for (i=FIRST_FPR; i<=LAST_FPR; i++) {
+ regsize[i] = l2zm(8L);
+ regtype[i] = &ftyp;
+ }
+
+ for (i=FIRST_CCR; i<=LAST_CCR; i++) {
+ regsize[i] = l2zm(4L);
+ regtype[i] = <yp;
+ }
+
+ for (i=FIRST_PAIR; i<FIRST_DOUBLE; i++) {
+ regsize[i] = l2zm(8L);
+ regtype[i] = &lltyp;
+ }
+
+ for (i=FIRST_DOUBLE; i<=LAST_PAIR; i++) {
+ regsize[i] = l2zm(8L);
+ regtype[i] = &dtyp;
+ }
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR] = l2zm(-128L);
+ t_min[SHORT] = l2zm(-32768L);
+ t_min[INT] = zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LONG] = t_min(INT);
+ t_min[LLONG] = zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT] = t_min(LLONG);
+ t_max[CHAR] = ul2zum(127L);
+ t_max[SHORT] = ul2zum(32767UL);
+ t_max[INT] = ul2zum(2147483647UL);
+ t_max[LONG] = t_max(INT);
+ t_max[LLONG] = zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT] = t_max(LLONG);
+ tu_max[CHAR] = ul2zum(255UL);
+ tu_max[SHORT] = ul2zum(65535UL);
+ tu_max[INT] = ul2zum(4294967295UL);
+ tu_max[LONG] = t_max(UNSIGNED|INT);
+ tu_max[LLONG] = zumkompl(ul2zum(0UL));
+ tu_max[MAXINT] = t_max(UNSIGNED|LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ regsa[ip] = regsa[sp] = regsa[lr] = regsa[pc] = 1;
+ regscratch[ip] = regscratch[sp] = regscratch[lr] = regscratch[pc] = 0;
+
+ if (LE_MODE)
+ arm_le_mode = 1;
+ if (BE_MODE)
+ arm_le_mode = 0;
+ if (ARM_DEFAULT)
+ thumb_default = 0;
+ if (THUMB_DEFAULT)
+ thumb_default = 1;
+ if (ELF_LABELS) {
+ labprefix = ".l";
+ idprefix = "";
+ }
+
+ target_macros = marray;
+
+
+ /* TODO: set argument registers */
+ declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+ declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+ declare_builtin("__divsint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__modsint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__lsrsint64",LLONG,LLONG,0,INT,0,1,0);
+ declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+ declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
+ declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
+ declare_builtin("__sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
+ declare_builtin("__uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
+ declare_builtin("__flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
+ declare_builtin("__flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);
+
+ declare_builtin("__flt32toflt64",DOUBLE,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt64toflt32",FLOAT,DOUBLE,0,0,0,1,0);
+
+
+ declare_builtin("__addflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__subflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__mulflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__divflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__negflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__cmpflt32",INT,FLOAT,0,FLOAT,0,1,0);
+
+ declare_builtin("__addflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__subflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__mulflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__divflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__negflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__cmpflt64",INT,DOUBLE,0,DOUBLE,0,1,0);
+
+
+ return 1;
+}
+
+
+void init_db(FILE *f)
+{
+}
+
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+/* A pointer MUST be returned in a register. The code-generator */
+/* has to simulate a pseudo register if necessary. */
+{
+ int tu = t->flags&NQ;
+
+ /* @@@ handle VFP */
+
+ if (tu==LLONG || tu==DOUBLE)
+ return FIRST_PAIR;
+
+ if (zmleq(szof(t),l2zm(4L)))
+ return FIRST_GPR;
+
+ return 0;
+}
+
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ if (r<FIRST_PAIR || r>LAST_PAIR)
+ return 0;
+
+ switch (r) {
+ case FIRST_PAIR:
+ p->r1 = FIRST_GPR;
+ p->r2 = FIRST_GPR+1;
+ return 1;
+ case FIRST_PAIR+1:
+ p->r1 = FIRST_GPR+2;
+ p->r2 = FIRST_GPR+3;
+ return 1;
+ case FIRST_PAIR+2:
+ p->r1 = FIRST_GPR+4;
+ p->r2 = FIRST_GPR+5;
+ return 1;
+ case FIRST_PAIR+3:
+ p->r1 = FIRST_GPR+6;
+ p->r2 = FIRST_GPR+7;
+ return 1;
+ case FIRST_PAIR+4:
+ p->r1 = FIRST_GPR+10;
+ p->r2 = FIRST_GPR+11;
+ return 1;
+ case FIRST_DOUBLE:
+ p->r1 = FIRST_FPR;
+ p->r2 = FIRST_FPR+1;
+ return 1;
+ case FIRST_DOUBLE+1:
+ p->r1 = FIRST_FPR+2;
+ p->r2 = FIRST_FPR+3;
+ return 1;
+ case FIRST_DOUBLE+2:
+ p->r1 = FIRST_FPR+4;
+ p->r2 = FIRST_FPR+5;
+ return 1;
+ case FIRST_DOUBLE+3:
+ p->r1 = FIRST_FPR+6;
+ p->r2 = FIRST_FPR+7;
+ return 1;
+ case FIRST_DOUBLE+4:
+ p->r1 = FIRST_FPR+8;
+ p->r2 = FIRST_FPR+9;
+ return 1;
+ case FIRST_DOUBLE+5:
+ p->r1 = FIRST_FPR+10;
+ p->r2 = FIRST_FPR+11;
+ return 1;
+ case FIRST_DOUBLE+6:
+ p->r1 = FIRST_FPR+12;
+ p->r2 = FIRST_FPR+13;
+ return 1;
+ case FIRST_DOUBLE+7:
+ p->r1 = FIRST_FPR+14;
+ p->r2 = FIRST_FPR+15;
+ return 1;
+ default:
+ ierror(0);
+ }
+
+ return 0;
+}
+
+
+int cost_savings(struct IC *p,int r,struct obj *o)
+/* estimate the cost-saving if object o from IC p is placed in */
+/* register r */
+{
+ int c = p->code;
+
+ /* @@@ FIXME */
+ if (o->flags & VKONST) {
+ if (o==&p->q1 && p->code==ASSIGN && (p->z.flags&DREFOBJ))
+ return 4;
+ else
+ return 2;
+ }
+ if (o->flags & DREFOBJ)
+ return 4;
+ if (c==SETRETURN && r==p->z.reg && !(o->flags&DREFOBJ))
+ return 3;
+ if (c==GETRETURN && r==p->q1.reg && !(o->flags&DREFOBJ))
+ return 3;
+ return 2;
+}
+
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if (r==0)
+ return 0;
+
+ if (t==0 && r>=FIRST_CCR && r<=LAST_CCR)
+ return 1;
+
+ t &= NQ;
+
+ if (ISFLOAT(t)) {
+ /* @@@ handle VFP */
+ if (t==FLOAT && r>=FIRST_GPR && r<=LAST_GPR)
+ return 1;
+ else if (r>=FIRST_PAIR && r<=LAST_PAIR)
+ return 1;
+ }
+ else if (t==POINTER && r>=FIRST_GPR && r<=LAST_GPR)
+ return 1;
+ else if (t>=CHAR && t<=LONG && r>=FIRST_GPR && r<=LAST_GPR)
+ return 1;
+ else if (t==LLONG && r>=FIRST_PAIR && r<=LAST_PAIR)
+ return 1;
+
+ return 0;
+}
+
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ if ((p->q1.flags&DREFOBJ) || (p->q2.flags&DREFOBJ) || (p->z.flags&DREFOBJ))
+ return 1;
+ /* ARM has no division/modulo instructions */
+ return 0;
+}
+
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* On the PowerPC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op = o & NQ;
+ int tp = t & NQ;
+
+ if ((op==INT||op==LONG||op==POINTER) && (tp==INT||tp==LONG||tp==POINTER))
+ return 0;
+ if (op==DOUBLE && tp==LDOUBLE)
+ return 0;
+ if (op==LDOUBLE && tp==DOUBLE)
+ return 0;
+ if(op==tp)
+ return 0;
+ return 1;
+}
+
+
+char *use_libcall(int c,int t,int t2)
+/* Return name of library function, if this node should be
+ implemented via libcall. */
+{
+ static char fname[16];
+ char *ret = NULL;
+
+ if (((c==MULT && aa<AA2) ||
+ (c>MULT && c<=MOD)) && (t&NQ) <= LONG) {
+ if ((t&UNSIGNED) && (c==DIV || c==MOD))
+ sprintf(fname,"__%s",ename[c]);
+ else
+ sprintf(fname,"__%ss",ename[c]);
+ ret = fname;
+ }
+
+ if(c==COMPARE){
+ if((t&NQ)==LLONG||ISFLOAT(t)){
+ sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }else{
+ t&=NU;
+ t2&=NU;
+ if(t==LDOUBLE) t=DOUBLE;
+ if(t2==LDOUBLE) t2=DOUBLE;
+ if(c==CONVERT){
+ if(t==t2) return 0;
+ if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+ if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+
+ if(ISFLOAT(t)){
+ sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64);
+ ret=fname;
+ }
+ if(ISFLOAT(t2)&&(t&NU)==LLONG){
+ sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+ if((t&NQ)==LLONG||ISFLOAT(t)){
+ if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+ if(t==(UNSIGNED|LLONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint64",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==LLONG){
+ sprintf(fname,"__%sint64",ename[c]);
+ ret=fname;
+ }else{
+ sprintf(fname,"__%s%s%s%ld",ename[c],(t&UNSIGNED)?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ title(f);
+
+ if (newobj && section!=SPECIAL)
+ emit(f,"%ld\n",zm2l(size));
+ else
+ emit(f,"\t.space\t%ld\n",zm2l(size));
+
+ newobj = 0;
+}
+
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ title(f);
+
+ if (zm2l(align) > 1)
+ emit(f,"\t.align\t2\n");
+}
+
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;
+ char *sec;
+
+ title(f);
+
+ if(v->clist)
+ constflag = is_const(v->vtyp);
+
+ if (isstatic(v->storage_class)) {
+ if (ISFUNC(v->vtyp->flags))
+ return;
+ if (!special_section(f,v)) {
+ if (v->clist && (!constflag || CONST_IN_DATA) && section!=DATA) {
+ emit(f,dataname);
+ if (f)
+ section = DATA;
+ }
+ if (v->clist && constflag && !CONST_IN_DATA && section!=RODATA) {
+ emit(f,rodataname);
+ if (f)
+ section = RODATA;
+ }
+ if (!v->clist && section!=BSS) {
+ emit(f,bssname);
+ if (f)
+ section = BSS;
+ }
+ }
+ if (v->clist || section==SPECIAL) {
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }
+ else
+ emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+ newobj = 1;
+ }
+
+ if (isextern(v->storage_class)) {
+ emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+ if (v->flags & (DEFINED|TENTATIVE)) {
+ if (!special_section(f,v)) {
+ if (v->clist && (!constflag || CONST_IN_DATA) && section!=DATA) {
+ emit(f,dataname);
+ if(f)
+ section = DATA;
+ }
+ if (v->clist && constflag && !CONST_IN_DATA && section!=RODATA) {
+ emit(f,rodataname);
+ if (f)
+ section = RODATA;
+ }
+ if (!v->clist && section!=BSS) {
+ emit(f,bssname);
+ if (f)
+ section = BSS;
+ }
+ }
+ if (v->clist || section==SPECIAL) {
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }
+ else {
+ emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,
+ v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+ }
+ newobj = 1;
+ }
+ }
+}
+
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ title(f);
+
+ if ((t&NQ) == POINTER)
+ t = UNSIGNED|LONG;
+ emit(f,"\t.%s\t",dct[t&NQ]);
+
+ if (!p->tree) {
+ if (ISFLOAT(t)) {
+ unsigned char *ip = (unsigned char *)&p->val.vdouble;
+
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ if ((t&NQ) != FLOAT)
+ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ else {
+ emitval(f,&p->val,t&NU);
+ }
+ }
+ else {
+ emit_obj(f,&p->tree->o,t&NU);
+ }
+
+ emitnl(f);
+ newobj = 0;
+}
+
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/* The main code-generation routine. */
+{
+ FILE *outfile = f;
+ struct IC *p_start = p;
+ int c,t,i,pass;
+ struct rpair rp;
+
+ if (DEBUG & 1)
+ printf("gen_code()\n");
+
+ current_function = v;
+ icnt = 0;
+ drefptr_array_label = 0;
+ argsize = 0;
+ rsavesize = 0;
+ maxrsaveoffs = 0;
+ needframe = 0;
+
+ for (c=1; c<=MAXR; c++)
+ regs[c] = regsa[c];
+
+ for (p=p_start; p; p=p->next) {
+ c = p->code;
+ t = p->typf & NU;
+
+ if (c == ALLOCREG) {
+ if (reg_pair(p->q1.reg,&rp)) {
+ regs[rp.r1] = 1;
+ regs[rp.r2] = 1;
+ }
+ regs[p->q1.reg] = 1;
+ continue;
+ }
+
+ if (c == FREEREG) {
+ if (reg_pair(p->q1.reg,&rp)) {
+ regs[rp.r1] = 0;
+ regs[rp.r2] = 0;
+ }
+ regs[p->q1.reg] = 0;
+ continue;
+ }
+
+ /* try MULT/DIV/MOD with powers of two */
+ if ((c==MULT || ((c==DIV || c==MOD) && (t&UNSIGNED))) &&
+ (t&NQ)<=LONG && isconst(p->q2.flags)) {
+ eval_const(&p->q2.val,t);
+ if (i = pof2(vmax)) {
+ if (c == MOD) {
+ vmax = zmsub(vmax,l2zm(1L));
+ p->code = AND;
+ }
+ else {
+ vmax = l2zm(i-1);
+ p->code = c==DIV ? RSHIFT : LSHIFT;
+ }
+ c = p->code;
+ gval.vmax = vmax;
+ eval_const(&gval,MAXINT);
+ if (c == AND) {
+ insert_const(&p->q2.val,t);
+ }
+ else {
+ insert_const(&p->q2.val,INT);
+ p->typf2 = INT;
+ }
+ }
+ }
+
+ if (c == CALL) {
+ needframe = 1;
+ if (argsize < zm2l(pushedargsize(p)))
+ argsize = zm2l(pushedargsize(p)); /* set max argsize */
+ }
+ }
+
+ /*peephole(p); @@@ FIXME */
+
+ for (c=i; i<=MAXR; i++) {
+ if (regsa[i] || regused[i])
+ BSET(regs_modified,i);
+ if (!regsa[i] && !regscratch[i] && regused[i])
+ needframe = 1;
+ }
+
+ /* determine word-aligned space for local variables */
+ localsize = ((zm2l(offset) + 3) / 4) * 4;
+ if (localsize > 0)
+ needframe = 1;
+
+ for (pass=0,f=NULL; pass<2; pass++,f=outfile) {
+ struct IC my_ic;
+ struct IC *p2;
+
+ if (pass) {
+ emit_dataptr_array(NULL); /* reset ptr-array */
+ icnt = 0;
+ function_top(f,v,argsize+localsize);
+ }
+
+ pushoffs = 0;
+
+ for (p2=p_start; p2; p2=p2->next) {
+ if (pass) {
+ p = p2;
+ }
+ else { /* work on a copy in first pass */
+ p = &my_ic;
+ *p = *p2;
+ }
+
+ c = p->code;
+ t = p->typf;
+
+ cg_freeall(f); /* reset internal register allocations */
+
+ if (icnt > MAXCODELINES) {
+ /* function has grown too big, emit all data-reference pointers first */
+ emit(f,"\tb\t%s%d\n",labprefix,++label);
+ emit_dataptr_array(f);
+ emit(f,"%s%d:\n",labprefix,label);
+ icnt = 0;
+ }
+
+ if (c == NOP) {
+ p->z.flags = 0;
+ continue;
+ }
+
+ if (c == ALLOCREG) {
+ if (reg_pair(p->q1.reg,&rp)) {
+ regs[rp.r1] = 1;
+ regs[rp.r2] = 1;
+ }
+ regs[p->q1.reg] = 1;
+ continue;
+ }
+
+ if (c == FREEREG) {
+ if (reg_pair(p->q1.reg,&rp)) {
+ regs[rp.r1] = 0;
+ regs[rp.r2] = 0;
+ }
+ regs[p->q1.reg] = 0;
+ continue;
+ }
+
+ if (c == LABEL) {
+ emit(f,"%s%d:\n",labprefix,t);
+ continue;
+ }
+
+ if (c == BRA) {
+ if (t==exit_label && framesize==0)
+ emit(f,ret);
+ else
+ emit(f,"\tb\t%s%d\n",labprefix,t);
+ continue;
+ }
+
+ if (c>=BEQ && c<BRA) {
+ emit(f,"\tb%s\t",ccs[c-BEQ]);
+ if (isreg(p->q1.flags)) {
+ ierror(0); /* @@@ was ist das? */
+ emit_obj(f,&p->q1,0);
+ emit(f,",");
+ }
+ emit(f,"%s%d\n",labprefix,t);
+ continue;
+ }
+
+ if (c == MOVETOREG) {
+ if (p->z.reg>=FIRST_GPR && p->z.reg<=LAST_GPR) {
+ load_reg(f,p,p->z.reg,&p->q1,t);
+ }
+ else if (reg_pair(p->z.reg,&rp)) {
+ BSET(regs_modified,p->z.reg);
+ load_regpair(f,p,&rp,&p->q1,t);
+ }
+ else
+ ierror(0); /* @@@ VFP registers */
+ p->z.flags = 0;
+ continue;
+ }
+
+ if (c == MOVEFROMREG) {
+ if (p->q1.reg>=FIRST_GPR && p->q1.reg<=LAST_GPR) {
+ store_reg(f,p,p->q1.reg,&p->z,t);
+ }
+ else if (reg_pair(p->q1.reg,&rp)) {
+ store_regpair(f,p,&rp,&p->z,t);
+ }
+ else
+ ierror(0); /* @@@ VFP registers */
+ p->z.flags = 0;
+ continue;
+ }
+
+ if ((c==ASSIGN || c==PUSH) &&
+ ((t&NQ)>POINTER || ((t&NQ)==CHAR && zm2l(opsize(p))!=1))) {
+ cg_memcopy(f,p);
+ p->z.flags = 0;
+ continue;
+ }
+
+ p = preload(f,p);
+ c = p->code;
+
+ if (c == SUBPFP)
+ c = SUB;
+ else if (c == ADDI2P)
+ c = ADD;
+ else if (c == SUBIFP)
+ c = SUB;
+
+ if (c == CONVERT) {
+ if (ISFLOAT(q1typ(p)) || ISFLOAT(ztyp(p))) /* @@@ */
+ ierror(0);
+
+ if (sizetab[q1typ(p)&NQ] < sizetab[ztyp(p)&NQ]) {
+ int sh = 0;
+
+ if ((q1typ(p)&NQ) == CHAR)
+ sh = 24;
+ else if ((q1typ(p)&NQ) == SHORT)
+ sh = 16;
+ else if (sizetab[ztyp(p)&NQ] > 4)
+ ierror(0); /* @@@ */
+
+ if (sh) {
+ registerize(f,p,&p->q1,q1typ(p));
+ emit(f,"\tmov\t%s,%s,lsl #%d\n",regnames[zreg],regnames[p->q1.reg],sh);
+ emit(f,"\tmov\t%s,%s,%csr #%d\n",regnames[zreg],regnames[zreg],
+ (q1typ(p)&UNSIGNED)?'l':'a',sh);
+ }
+ }
+ save_result(f,p);
+ continue;
+ }
+
+ if (c == KOMPLEMENT) {
+ registerize(f,p,&p->q1,t);
+ emit(f,"\tmvn\t%s,%s\n",regnames[zreg],regnames[p->q1.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if (c == SETRETURN) {
+ load_reg(f,p,p->z.reg,&p->q1,t);
+ BSET(regs_modified,p->z.reg);
+ continue;
+ }
+
+ if (c == GETRETURN) {
+ if (p->q1.reg) { /* REG-flag is not set!? */
+ zreg = p->q1.reg;
+ save_result(f,p);
+ }
+ else
+ p->z.flags = 0;
+ continue;
+ }
+
+ if (c == CALL) {
+ if ((p->q1.flags & (VAR|DREFOBJ))==VAR &&
+ p->q1.v->fi && p->q1.v->fi->inline_asm) {
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ }
+ else if (p->q1.flags & DREFOBJ) {
+ int reg;
+
+ if (p->q1.flags & REG) {
+ reg = p->q1.reg;
+ }
+ else {
+ reg = cg_getreg(f,p);
+ load_reg(f,p,reg,&p->q1,POINTER);
+ }
+ emit(f,"\tmov\t%s,%s\n",regnames[lr],regnames[pc]);
+ if (aa < AA4T)
+ emit(f,"\tmov\t%s,%s\n",regnames[pc],regnames[reg]);
+ else
+ emit(f,"\tbx\t%s\n",regnames[reg]);
+ }
+ else {
+ emit(f,"\tbl\t");
+ emit_obj(f,&p->q1,t);
+ emitnl(f);
+ }
+
+ pushoffs -= zm2l(pushedargsize(p));
+
+ if ((p->q1.flags & (VAR|DREFOBJ))==VAR &&
+ p->q1.v->fi && (p->q1.v->fi->flags & ALL_REGS)) {
+ bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+ }
+ else{
+ int i;
+
+ for (i=1; i<=MAXR; i++) {
+ if (regscratch[i])
+ BSET(regs_modified,i);
+ }
+ }
+ continue;
+ }
+
+ if (c == PUSH) {
+ if (t == 0)
+ ierror(0);
+ registerize(f,p,&p->q1,t);
+ emit(f,"\tstr\t%s,[%s,#%ld]\n",
+ regnames[p->q1.reg],regnames[sp],pushoffs);
+ pushoffs += zm2l(opsize(p));
+ continue;
+ }
+
+ if (c == ASSIGN) {
+ if (t == 0)
+ ierror(0);
+ if (isreg(p->q1.flags))
+ zreg = p->q1.reg;
+ else
+ load_reg(f,p,zreg,&p->q1,t);
+ save_result(f,p);
+ continue;
+ }
+
+ if (c == ADDRESS) {
+ load_address(f,zreg,&p->q1,POINTER);
+ save_result(f,p);
+ continue;
+ }
+
+ if (c == MINUS) {
+ registerize(f,p,&p->q1,t);
+ emit(f,"\trsb\t%s,%s,#0\n",regnames[zreg],regnames[p->q1.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if (c == TEST) {
+ registerize(f,p,&p->q1,t);
+ emit(f,"\tteq\t%s,#0\n",regnames[p->q1.reg]);
+ continue;
+ }
+
+ if (c == COMPARE) {
+ if (!isconst(p->q1.flags))
+ registerize(f,p,&p->q1,t);
+ emit(f,"\tcmp\t%s,",regnames[p->q1.reg]);
+ emit_obj(f,&p->q2,t);
+ emitnl(f);
+ continue;
+ }
+
+ if ((c>=OR && c<=AND)) {
+ registerize(f,p,&p->q1,t);
+ if (!isconst(p->q2.flags))
+ registerize(f,p,&p->q2,t);
+ emit(f,"\t%s\t%s,%s,",logicals[c-OR],regnames[zreg],
+ regnames[p->q1.reg]);
+ emit_obj(f,&p->q2,t);
+ emitnl(f);
+ save_result(f,p);
+ continue;
+ }
+
+ if (c>=LSHIFT && c<=RSHIFT) {
+ registerize(f,p,&p->q1,t);
+ if (!isconst(p->q2.flags))
+ registerize(f,p,&p->q2,t);
+ emit(f,"\tmov\t%s,%s,%s ",regnames[zreg],regnames[p->q1.reg],
+ shifts[(t&UNSIGNED)!=0][c-LSHIFT]);
+ emit_obj(f,&p->q2,t);
+ emitnl(f);
+ save_result(f,p);
+ continue;
+ }
+
+ if (c>=ADD && c<=SUB) {
+ registerize(f,p,&p->q1,t);
+ if (!isconst(p->q2.flags))
+ registerize(f,p,&p->q2,t);
+ emit(f,"\t%s\t%s,%s,",c==ADD?"add":"sub",
+ regnames[zreg],regnames[p->q1.reg]);
+ emit_obj(f,&p->q2,t);
+ emitnl(f);
+ save_result(f,p);
+ continue;
+ }
+
+ if (c==MULT && aa>=AA2 && sizetab[t&NQ]<=4) {
+ registerize(f,p,&p->q1,t);
+ registerize(f,p,&p->q2,t);
+ emit(f,"\tmul\t%s,%s,%s\n",
+ regnames[zreg],regnames[p->q1.reg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if (pass) {
+ pric2(stdout,p);
+ ierror(0);
+ }
+ }
+ }
+
+ cg_freeall(f);
+ function_bottom(f,v,argsize+localsize+rsavesize);
+
+#if 0 /* @@@ wozu? */
+ if (stack_valid) {
+ if (!v->fi)
+ v->fi = new_fi();
+ v->fi->flags |= ALL_STACK;
+ v->fi->stack1 = stack;
+ }
+ emit(f,"; stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+#endif
+}
+
+
+int shortcut(int code,int typ)
+{
+ return 0;
+}
+
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+ int f;
+
+ if (!m || !t)
+ ierror(0);
+
+ f = t->flags & NQ;
+
+ if (f<=LONG || f==POINTER) {
+ if (m->gregs >= GPR_ARGS)
+ return 0;
+ else
+ return FIRST_GPR + m->gregs++;
+ }
+
+ if (f == LLONG) {
+ if (m->gregs >= GPR_ARGS-1)
+ return 0;
+ else
+ ierror(0); /* @@@ check ABI if odd registers are skipped!? */
+ }
+
+ if (ISFLOAT(f)) {
+#if 0 /* @@@ VFP only! */
+ if (m->fregs >= FPR_ARGS)
+ return 0;
+ else
+ return FIRST_DOUBLE + m->fregs++;
+#endif
+ }
+
+ return 0;
+}
+
+
+int emit_peephole(void)
+/* This function will not optimize anything, but just update the
+ number of lines counter, icnt, for the current function.
+ It is required to estimate if a data-reference-pointer array
+ is still reachable with a 12-bit offset. */
+{
+ int entries;
+
+ entries = emit_f ? EMIT_BUF_DEPTH : emit_l - emit_f + 1;
+ icnt += entries;
+ return 0;
+}
+
+
+int handle_pragma(const char *s)
+{
+ return 0;
+}
+
+
+void cleanup_cg(FILE *f)
+{
+}
+
+
+void cleanup_db(FILE *f)
+{
+ if (f)
+ section = -1;
+}
diff --git a/machines/arm/machine.dt b/machines/arm/machine.dt
new file mode 100755
index 0000000..47b1bfa
--- /dev/null
+++ b/machines/arm/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S32BULE S32BUBE
+
+
diff --git a/machines/arm/machine.h b/machines/arm/machine.h
new file mode 100755
index 0000000..7730379
--- /dev/null
+++ b/machines/arm/machine.h
@@ -0,0 +1,141 @@
+/*
+ * ARM code generator
+ * Written by Frank Wille <frank@phoenix.owl.de>
+ */
+
+/* built-time configurable options: */
+#define NUM_GPRS 16
+#define NUM_FPRS 16
+#define NUM_CCRS 1
+#define NUM_PAIRS 13
+
+#include "dt.h"
+
+/* internally used by the backend */
+#define FIRST_GPR 1
+#define LAST_GPR (FIRST_GPR+NUM_GPRS-1)
+#define FIRST_FPR (LAST_GPR+1)
+#define LAST_FPR (FIRST_FPR+NUM_FPRS-1)
+#define FIRST_CCR (LAST_FPR+1)
+#define LAST_CCR (FIRST_CCR+NUM_CCRS-1)
+#define FIRST_PAIR (LAST_CCR+1)
+#define FIRST_DOUBLE (FIRST_PAIR+5)
+#define LAST_PAIR (FIRST_PAIR+NUM_PAIRS-1)
+
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Currently possible are (const,gpr) and (gpr,gpr) */
+struct AddressingMode{
+ int never_used;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR NUM_GPRS+NUM_FPRS+NUM_CCRS+NUM_PAIRS
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 10
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P INT
+
+/* This specifies the largest integer type that can be added to a */
+/* pointer. */
+#define MAXADDI2P LONG
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN (!arm_le_mode)
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN (arm_le_mode)
+
+extern int arm_le_mode;
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+/* Parameters are sometimes passed in registers without __reg. */
+#define HAVE_REGPARMS 1
+
+/* Parameters on the stack should be pushed in order rather than */
+/* in reverse order. */
+#define ORDERED_PUSH 1
+
+/* Structure for reg_parm(). */
+struct reg_handle{
+ unsigned long gregs;
+ unsigned long fregs;
+};
+
+/* Number registers used for function arguments */
+#define GPR_ARGS 4
+#define FPR_ARGS 4
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have no target-specific pragmas */
+#undef HAVE_TARGET_PRAGMAS
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have to implement our own cost-functions to adapt
+ register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output, this can be used to do
+ peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/* We have asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+ optimizations on code which can already be implemented by efficient
+ assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+ etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#undef HAVE_INT_SIZET
+
+/* we have register-pairs */
+#define HAVE_REGPAIRS 1
+
+#define JUMP_TABLE_DENSITY 0.8
+#define JUMP_TABLE_LENGTH 12
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
diff --git a/machines/bc16/machine.c b/machines/bc16/machine.c
new file mode 100755
index 0000000..82ab96f
--- /dev/null
+++ b/machines/bc16/machine.c
@@ -0,0 +1,1179 @@
+/* Example backend for vbcc, it models a generic 32bit RISC or CISC
+ CPU.
+
+ Configurable at build-time are:
+ - number of (32bit) general-purpose-registers
+ - number of (64bit) floating-point-registers
+ - number of (8bit) condition-code-registers
+ - mechanism for stack-arguments (moving ot fixed sp)
+
+ It allows to select as run-time-options:
+ - two- or three-address code
+ - memory operands or load-store-architecture
+ - number of register-arguments
+ - number of caller-save-registers
+*/
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc bc16 code-generator V0.1 (c) in 2021 by Volker Barthelmann";
+
+/* Commandline-flags the code-generator accepts:
+ 0: just a flag
+ VALFLAG: a value must be specified
+ STRINGFLAG: a string can be specified
+ FUNCFLAG: a function will be called
+ apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]={0,0,
+ VALFLAG,VALFLAG,VALFLAG,
+ 0,0,
+ VALFLAG,VALFLAG,0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+ they collide with the frontend */
+char *g_flags_name[MAXGF]={"three-addr","load-store",
+ "volatile-gprs","volatile-fprs","volatile-ccrs",
+ "imm-ind","gpr-ind",
+ "gpr-args","fpr-args","use-commons"};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. will be initialized in init_cg(),
+ register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+ estimated cost-saving can be obtained by several registers, the
+ one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__interrupt",0};
+
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+#define THREE_ADDR (g_flags[0]&USEDFLAG)
+#define LOAD_STORE (g_flags[1]&USEDFLAG)
+#define VOL_GPRS ((g_flags[2]&USEDFLAG)?g_flags_val[2].l:NUM_GPRS/2)
+#define VOL_FPRS ((g_flags[3]&USEDFLAG)?g_flags_val[3].l:NUM_FPRS/2)
+#define VOL_CCRS ((g_flags[4]&USEDFLAG)?g_flags_val[4].l:NUM_CCRS/2)
+#define IMM_IND ((g_flags[5]&USEDFLAG)?1:0)
+#define GPR_IND ((g_flags[6]&USEDFLAG)?2:0)
+#define GPR_ARGS ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:0)
+#define FPR_ARGS ((g_flags[8]&USEDFLAG)?g_flags_val[8].l:0)
+#define USE_COMMONS (g_flags[9]&USEDFLAG)
+
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]= {1,1,2,4,4,4,4,8,8,1,4,1,1,1,4,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp={LONG},ldbl={DOUBLE},lchar={CHAR};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+ "__GENERIC__",
+ 0};
+
+/* special registers */
+static int sp; /* Stackpointer */
+static int t1,t2,t3; /* temporary gprs */
+static int f1,f2,f3; /* temporary fprs */
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\t.text\n",
+ *dataname="\t.data\n",
+ *bssname="",
+ *rodataname="\t.section\t.rodata\n";
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+#if FIXED_SP
+/* variables to calculate the size and partitioning of the stack-frame
+ in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+#else
+/* variables to keep track of the current stack-offset in the case of
+ a moving stack-pointer */
+static long notpopped,dontpop,pushed,stackoffset,maxpushed;
+#endif
+
+static long localsize,rsavesize,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+ stack-pointer; we use a layout like this:
+ ------------------------------------------------
+ | arguments to this function |
+ ------------------------------------------------
+ | return-address [size=4] |
+ ------------------------------------------------
+ | caller-save registers [size=rsavesize] |
+ ------------------------------------------------
+ | local variables [size=localsize] |
+ ------------------------------------------------
+ | arguments to called functions [size=argsize] |
+ ------------------------------------------------
+ All sizes will be aligned as necessary.
+ In the case of FIXED_SP, the stack-pointer will be adjusted at
+ function-entry to leave enough space for the arguments and have it
+ aligned to 16 bytes. Therefore, when calling a function, the
+ stack-pointer is always aligned to 16 bytes.
+ For a moving stack-pointer, the stack-pointer will usually point
+ to the bottom of the area for local variables, but will move while
+ arguments are put on the stack.
+
+ This is just an example layout. Other layouts are also possible.
+*/
+
+static void push(int i)
+{
+ pushed-=i;
+ if(pushed<maxpushed)
+ maxpushed=pushed;
+}
+
+static void pop(int i)
+{
+ pushed+=i;
+ if(pushed>0) ierror(0);
+}
+
+static long real_offset(struct obj *o)
+{
+ long off=zm2l(o->v->offset);
+ if(off<0){
+ /* function parameter */
+ off=localsize+rsavesize+4-off-zm2l(maxalign);
+ }
+
+#if FIXED_SP
+ off+=argsize;
+#else
+ off+=stackoffset;
+#endif
+ off+=zm2l(o->val.vmax);
+ return off;
+}
+
+/* Initializes an addressing-mode structure and returns a pointer to
+ that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ am.offset=offset;
+ return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+ char *sec;
+ if(!v->vattr) return 0;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return 0;
+ sec+=strlen("section(");
+ emit(f,"\t.section\t");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/* Generates code to load the address of a variable into register r. */
+{
+ if(!(o->flags&VAR)) ierror(0);
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+ long off=real_offset(o);
+ if(THREE_ADDR){
+ emit(f,"\tadd.%s\t%s,%s,%ld\n",dt(POINTER),regnames[r],regnames[sp],off);
+ }else{
+ emit(f,"\tmov.%s\t%s,%s\n",dt(POINTER),regnames[r],regnames[sp]);
+ if(off)
+ emit(f,"\tadd.%s\t%s,%ld\n",dt(POINTER),regnames[r],off);
+ }
+ }else{
+ emit(f,"\tmov.%s\t%s,",dt(POINTER),regnames[r]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }
+}
+/* Generates code to load a memory object into register r. tmp is a
+ general purpose register which may be used. tmp can be r. */
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+ type&=NU;
+ if(o->flags&VARADR){
+ load_address(f,r,o,POINTER);
+ }else{
+ if((o->flags&(REG|DREFOBJ))==REG&&o->reg==r)
+ return;
+ emit(f,"\tmov.%s\t%s,",dt(type),regnames[r]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }
+}
+
+/* Generates code to store register r into memory object o. */
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+ type&=NQ;
+ emit(f,"\tmov.%s\t",dt(type));
+ emit_obj(f,o,type);
+ emit(f,",%s\n",regnames[r]);
+}
+
+/* Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+
+static struct IC *preload(FILE *,struct IC *);
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
+
+/* compare if two objects are the same */
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+ if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
+ return 1;
+ if(o1->flags==o2->flags&&o1->am==o2->am){
+ if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+ if(!(o1->flags®)||o1->reg==o2->reg){
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Does some pre-processing like fetching operands from memory to
+ registers etc. */
+static struct IC *preload(FILE *f,struct IC *p)
+{
+ int r;
+
+ if(isreg(q1))
+ q1reg=p->q1.reg;
+ else
+ q1reg=0;
+
+ if(isreg(q2))
+ q2reg=p->q2.reg;
+ else
+ q2reg=0;
+
+ if(isreg(z)&&(THREE_ADDR||!compare_objects(&p->q2,&p->z))){
+ zreg=p->z.reg;
+ }else{
+ if(ISFLOAT(ztyp(p)))
+ zreg=f1;
+ else
+ zreg=t1;
+ }
+
+ if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am){
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,t1,&p->q1,q1typ(p));
+ p->q1.reg=t1;
+ p->q1.flags|=(REG|DREFOBJ);
+ }
+ if(p->q1.flags&&LOAD_STORE&&!isreg(q1)){
+ if(p->code==ASSIGN&&isreg(z))
+ q1reg=p->z.reg;
+ else if(ISFLOAT(q1typ(p)))
+ q1reg=f1;
+ else
+ q1reg=t1;
+ load_reg(f,q1reg,&p->q1,q1typ(p));
+ p->q1.reg=q1reg;
+ p->q1.flags=REG;
+ }
+
+ if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am){
+ p->q2.flags&=~DREFOBJ;
+ load_reg(f,t1,&p->q2,q2typ(p));
+ p->q2.reg=t1;
+ p->q2.flags|=(REG|DREFOBJ);
+ }
+ if(p->q2.flags&&LOAD_STORE&&!isreg(q2)){
+ if(ISFLOAT(q2typ(p)))
+ q2reg=f2;
+ else
+ q2reg=t2;
+ load_reg(f,q2reg,&p->q2,q2typ(p));
+ p->q2.reg=q2reg;
+ p->q2.flags=REG;
+ }
+ return p;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+ if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
+ p->z.flags&=~DREFOBJ;
+ load_reg(f,t2,&p->z,POINTER);
+ p->z.reg=t2;
+ p->z.flags|=(REG|DREFOBJ);
+ }
+ if(isreg(z)){
+ if(p->z.reg!=zreg)
+ emit(f,"\tmov.%s\t%s,%s\n",dt(ztyp(p)),regnames[p->z.reg],regnames[zreg]);
+ }else{
+ store_reg(f,zreg,&p->z,ztyp(p));
+ }
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+ if(p->am){
+ if(p->am->flags&GPR_IND) emit(f,"(%s,%s)",regnames[p->am->offset],regnames[p->am->base]);
+ if(p->am->flags&IMM_IND) emit(f,"(%ld,%s)",p->am->offset,regnames[p->am->base]);
+ return;
+ }
+ if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if(p->flags&DREFOBJ) emit(f,"(");
+ if(p->flags®){
+ emit(f,"%s",regnames[p->reg]);
+ }else if(p->flags&VAR) {
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+ emit(f,"%ld(%s)",real_offset(p),regnames[sp]);
+ else{
+ if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ }
+ }
+ if(p->flags&KONST){
+ emitval(f,&p->val,t&NU);
+ }
+ if(p->flags&DREFOBJ) emit(f,")");
+}
+
+/* Test if there is a sequence of FREEREGs containing FREEREG reg.
+ Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+ while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+ if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+ p=p->next;
+ }
+ return 0;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+ int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+ for(;p;p=p->next){
+ c=p->code;
+ if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+ if(c==LABEL) exit_label=p->typf;
+
+ /* Try const(reg) */
+ if(IMM_IND&&(c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+ int base;zmax of;struct obj *o;
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ if(1/*zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))*/){
+ r=p->z.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ am->base=base;
+ am->offset=zm2l(of);
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+ /* Try reg,reg */
+ if(GPR_IND&&c==ADDI2P&&isreg(q2)&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+ int base,idx;struct obj *o;
+ r=p->z.reg;idx=p->q2.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||(q1typ(p2)&NQ)==LLONG) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||(q2typ(p2)&NQ)==LLONG) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||(ztyp(p2)&NQ)==LLONG) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=GPR_IND;
+ am->base=base;
+ am->offset=idx;
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+ rsavesize=0;
+ if(!special_section(f,v)&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+}
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+ emit(f,ret);
+}
+
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+int init_cg(void)
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(8L);
+ char_bit=l2zm(8L);
+ stackalign=l2zm(4);
+
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+
+ regnames[0]="noreg";
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"gpr%d",i-FIRST_GPR);
+ regsize[i]=l2zm(4L);
+ regtype[i]=<yp;
+ }
+ for(i=FIRST_FPR;i<=LAST_FPR;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"fpr%d",i-FIRST_FPR);
+ regsize[i]=l2zm(8L);
+ regtype[i]=&ldbl;
+ }
+ for(i=FIRST_CCR;i<=LAST_CCR;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"ccr%d",i-FIRST_CCR);
+ regsize[i]=l2zm(1L);
+ regtype[i]=&lchar;
+ }
+
+ /* Use multiple ccs. */
+ multiple_ccs=0;
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LONG]=t_min(INT);
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=ul2zum(2147483647UL);
+ t_max[LONG]=t_max(INT);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=ul2zum(4294967295UL);
+ tu_max[LONG]=t_max(UNSIGNED|INT);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ /* This is not optimal but simple. */
+ sp=FIRST_GPR;
+ t1=FIRST_GPR+1;
+ t2=FIRST_GPR+2;
+ f1=FIRST_FPR;
+ f2=FIRST_FPR+1;
+ regsa[t1]=regsa[t2]=1;
+ regsa[f1]=regsa[f2]=1;
+ regsa[sp]=1;
+ regscratch[t1]=regscratch[t2]=0;
+ regscratch[f1]=regscratch[f2]=0;
+ regscratch[sp]=0;
+
+ for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++)
+ regscratch[i]=1;
+ for(i=FIRST_FPR;i<=LAST_FPR-VOL_FPRS;i++)
+ regscratch[i]=1;
+ for(i=FIRST_CCR;i<=LAST_CCR-VOL_CCRS;i++)
+ regscratch[i]=1;
+
+ target_macros=marray;
+
+
+ return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+/* A pointer MUST be returned in a register. The code-generator */
+/* has to simulate a pseudo register if necessary. */
+{
+ if(ISFLOAT(t->flags))
+ return FIRST_FPR+2;
+ if(ISSTRUCT(t->flags)||ISUNION(t->flags))
+ return 0;
+ if(zmleq(szof(t),l2zm(4L)))
+ return FIRST_GPR+3;
+ else
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+ register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+ int c=p->code;
+ if(o->flags&VKONST){
+ if(!LOAD_STORE)
+ return 0;
+ if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
+ return 4;
+ else
+ return 2;
+ }
+ if(o->flags&DREFOBJ)
+ return 4;
+ if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+ if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+ return 2;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(r==0)
+ return 0;
+ t&=NQ;
+ if(t==0&&r>=FIRST_CCR&&r<=LAST_CCR)
+ return 1;
+ if(ISFLOAT(t)&&r>=FIRST_FPR&&r<=LAST_FPR)
+ return 1;
+ if(t==POINTER&&r>=FIRST_GPR&&r<=LAST_GPR)
+ return 1;
+ if(t>=CHAR&&t<=LONG&&r>=FIRST_GPR&&r<=LAST_GPR)
+ return 1;
+ return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* On the PowerPC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op=o&NQ,tp=t&NQ;
+ if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
+ return 0;
+ if(op==DOUBLE&&tp==LDOUBLE) return 0;
+ if(op==LDOUBLE&&tp==DOUBLE) return 0;
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ if(newobj&§ion!=SPECIAL)
+ emit(f,"%ld\n",zm2l(size));
+ else
+ emit(f,"\t.space\t%ld\n",zm2l(size));
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ if(zm2l(align)>1) emit(f,"\t.align\t2\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;char *sec;
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(v->clist||section==SPECIAL){
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }else
+ emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+ newobj=1;
+ }
+ if(v->storage_class==EXTERN){
+ emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+ if(v->flags&(DEFINED|TENTATIVE)){
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(v->clist||section==SPECIAL){
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ emit(f,"\tdc.%s\t",dt(t&NQ));
+ if(!p->tree){
+ if(ISFLOAT(t)){
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ if((t&NQ)!=FLOAT){
+ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ }else{
+ emitval(f,&p->val,t&NU);
+ }
+ }else{
+ emit_obj(f,&p->tree->o,t&NU);
+ }
+ emit(f,"\n");newobj=0;
+}
+
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/* The main code-generation. */
+{
+ int c,t,i;
+ struct IC *m;
+ argsize=0;
+ if(DEBUG&1) printf("gen_code()\n");
+ for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+ maxpushed=0;
+
+ /*FIXME*/
+ ret="\trts\n";
+
+ for(m=p;m;m=m->next){
+ c=m->code;t=m->typf&NU;
+ if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
+ if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
+
+ /* convert MULT/DIV/MOD with powers of two */
+ if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+ eval_const(&m->q2.val,t);
+ i=pof2(vmax);
+ if(i){
+ if(c==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ m->code=AND;
+ }else{
+ vmax=l2zm(i-1);
+ if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+ }
+ c=m->code;
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ if(c==AND){
+ insert_const(&m->q2.val,t);
+ }else{
+ insert_const(&m->q2.val,INT);
+ p->typf2=INT;
+ }
+ }
+ }
+#if FIXED_SP
+ if(c==CALL&&argsize<zm2l(m->q2.val.vmax)) argsize=zm2l(m->q2.val.vmax);
+#endif
+ }
+ peephole(p);
+
+ for(c=1;c<=MAXR;c++){
+ if(regsa[c]||regused[c]){
+ BSET(regs_modified,c);
+ }
+ }
+
+ localsize=(zm2l(offset)+3)/4*4;
+#if FIXED_SP
+ /*FIXME: adjust localsize to get an aligned stack-frame */
+#endif
+
+ function_top(f,v,localsize);
+
+#if FIXED_SP
+ pushed=0;
+#endif
+
+ for(;p;p=p->next){
+ c=p->code;t=p->typf;
+ if(c==NOP) {p->z.flags=0;continue;}
+ if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
+ if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
+ if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);continue;}
+ if(c==BRA){
+ if(0/*t==exit_label&&framesize==0*/)
+ emit(f,ret);
+ else
+ emit(f,"\tb\t%s%d\n",labprefix,t);
+ continue;
+ }
+ if(c>=BEQ&&c<BRA){
+ emit(f,"\tb%s\t",ccs[c-BEQ]);
+ if(isreg(q1)){
+ emit_obj(f,&p->q1,0);
+ emit(f,",");
+ }
+ emit(f,"%s%d\n",labprefix,t);
+ continue;
+ }
+ if(c==MOVETOREG){
+ load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+ continue;
+ }
+ if(c==MOVEFROMREG){
+ store_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+ continue;
+ }
+ if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+ ierror(0);
+ }
+ /* switch commutative operands if suitable */
+ if(c==ADD||c==MULT||c==AND||c==XOR||c==OR){
+ if(compare_objects(&p->q2,&p->z)){
+ struct obj tmp;
+ tmp=p->q1;
+ p->q1=p->q2;
+ p->q2=tmp;
+ }
+ }
+
+ p=preload(f,p);
+ c=p->code;
+ if(c==SUBPFP) c=SUB;
+ if(c==ADDI2P) c=ADD;
+ if(c==SUBIFP) c=SUB;
+ if(c==CONVERT){
+ if(ISFLOAT(q1typ(p))||ISFLOAT(ztyp(p))) ierror(0);
+ if(sizetab[q1typ(p)&NQ]<sizetab[ztyp(p)&NQ]){
+ if(q1typ(p)&UNSIGNED)
+ emit(f,"\tzext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+ else
+ emit(f,"\tsext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+ }
+ save_result(f,p);
+ continue;
+ }
+ if(c==KOMPLEMENT){
+ load_reg(f,zreg,&p->q1,t);
+ emit(f,"\tcpl.%s\t%s\n",dt(t),regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c==SETRETURN){
+ load_reg(f,p->z.reg,&p->q1,t);
+ BSET(regs_modified,p->z.reg);
+ continue;
+ }
+ if(c==GETRETURN){
+ if(p->q1.reg){
+ zreg=p->q1.reg;
+ save_result(f,p);
+ }else
+ p->z.flags=0;
+ continue;
+ }
+ if(c==CALL){
+ int reg;
+ /*FIXME*/
+#if 0
+ if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+ if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+ stack=framesize+zum2ul(p->q1.v->fi->stack1);
+ }else
+ stack_valid=0;
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ }else{
+ emit(f,"\tcall\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ /*FIXME*/
+#if FIXED_SP
+ pushed-=zm2l(p->q2.val.vmax);
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+ bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+ }else{
+ int i;
+ for(i=1;i<=MAXR;i++){
+ if(regscratch[i]) BSET(regs_modified,i);
+ }
+ }
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(t==0) ierror(0);
+ if(c==PUSH){
+#if FIXED_SP
+ emit(f,"\tmov.%s\t%ld(%s),",dt(t),pushed,regnames[sp]);
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ pushed+=zm2l(p->q2.val.vmax);
+#else
+ emit(f,"\tpush.%s\t",dt(t));
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ push(zm2l(p->q2.val.vmax));
+#endif
+ continue;
+ }
+ if(c==ASSIGN){
+ load_reg(f,zreg,&p->q1,t);
+ save_result(f,p);
+ }
+ continue;
+ }
+ if(c==ADDRESS){
+ load_address(f,zreg,&p->q1,POINTER);
+ save_result(f,p);
+ continue;
+ }
+ if(c==MINUS){
+ load_reg(f,zreg,&p->q1,t);
+ emit(f,"\tneg.%s\t%s\n",dt(t),regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c==TEST){
+ emit(f,"\ttst.%s\t",dt(t));
+ if(multiple_ccs)
+ emit(f,"%s,",regnames[zreg]);
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ if(multiple_ccs)
+ save_result(f,p);
+ continue;
+ }
+ if(c==COMPARE){
+ emit(f,"\tcmp.%s\t",dt(t));
+ if(multiple_ccs)
+ emit(f,"%s,",regnames[zreg]);
+ emit_obj(f,&p->q1,t);
+ emit(f,",");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ if(multiple_ccs)
+ save_result(f,p);
+ continue;
+ }
+ if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)){
+ if(!THREE_ADDR)
+ load_reg(f,zreg,&p->q1,t);
+ if(c>=OR&&c<=AND)
+ emit(f,"\t%s.%s\t%s,",logicals[c-OR],dt(t),regnames[zreg]);
+ else
+ emit(f,"\t%s.%s\t%s,",arithmetics[c-LSHIFT],dt(t),regnames[zreg]);
+ if(THREE_ADDR){
+ emit_obj(f,&p->q1,t);
+ emit(f,",");
+ }
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ save_result(f,p);
+ continue;
+ }
+ pric2(stdout,p);
+ ierror(0);
+ }
+ function_bottom(f,v,localsize);
+ if(stack_valid){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=stack;
+ }
+ emit(f,"# stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int code,int typ)
+{
+ return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+ int f;
+ f=t->flags&NQ;
+ if(f<=LONG||f==POINTER){
+ if(m->gregs>=GPR_ARGS)
+ return 0;
+ else
+ return FIRST_GPR+3+m->gregs++;
+ }
+ if(ISFLOAT(f)){
+ if(m->fregs>=FPR_ARGS)
+ return 0;
+ else
+ return FIRST_FPR+2+m->fregs++;
+ }
+ return 0;
+}
+
+int handle_pragma(const char *s)
+{
+}
+void cleanup_cg(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+ if(f) section=-1;
+}
+
diff --git a/machines/bc16/machine.dt b/machines/bc16/machine.dt
new file mode 100755
index 0000000..cd2cdef
--- /dev/null
+++ b/machines/bc16/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S16BUBE S16BULE
+
+
diff --git a/machines/bc16/machine.h b/machines/bc16/machine.h
new file mode 100755
index 0000000..83579be
--- /dev/null
+++ b/machines/bc16/machine.h
@@ -0,0 +1,153 @@
+/* Example backend for vbcc, it models a generic 32bit RISC or CISC
+ CPU.
+
+ Configurable at build-time are:
+ - number of (32bit) general-purpose-registers
+ - number of (64bit) floating-point-registers
+ - number of (8bit) condition-code-registers
+ - mechanism for stack-arguments (moving ot fixed sp)
+
+ It allows to select as run-time-options:
+ - two- or three-address code
+ - memory operands or load-store-architecture
+ - number of register-arguments
+ - number of caller-save-registers
+*/
+
+/* buil-time configurable options: */
+#define NUM_GPRS 8
+#define NUM_FPRS 0
+#define NUM_CCRS 1
+#define FIXED_SP 0
+
+#include "dt.h"
+
+/* internally used by the backend */
+#define FIRST_GPR 1
+#define LAST_GPR (FIRST_GPR+NUM_GPRS-1)
+#define FIRST_FPR (LAST_GPR+1)
+#define LAST_FPR (FIRST_FPR+NUM_FPRS-1)
+#define FIRST_CCR (LAST_FPR+1)
+#define LAST_CCR (FIRST_CCR+NUM_CCRS-1)
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Currently possible are (const,gpr) and (gpr,gpr) */
+struct AddressingMode{
+ int flags;
+ int base;
+ long offset;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR NUM_GPRS+NUM_FPRS+NUM_CCRS
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 20
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P INT
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 0
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 1
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+/* Parameters are sometimes passed in registers without __reg. */
+#define HAVE_REGPARMS 1
+
+/* Parameters on the stack should be pushed in order rather than */
+/* in reverse order. */
+#define ORDERED_PUSH FIXED_SP
+
+/* Structure for reg_parm(). */
+struct reg_handle{
+ unsigned long gregs;
+ unsigned long fregs;
+};
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt
+ register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output, this can be used to do
+ peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/* We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+ optimizations on code which can already be implemented by efficient
+ assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+ etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#undef HAVE_INT_SIZET
+
+/* we do not need register-pairs */
+#undef HAVE_REGPAIRS
+
+
+/* do not create CONVERT ICs from integers smaller than int to floats */
+#define MIN_INT_TO_FLOAT_TYPE INT
+
+/* do not create CONVERT ICs from floats to ints smaller than int */
+#define MIN_FLOAT_TO_INT_TYPE INT
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 1
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 1
+
+/* convert multiplications/division by powers of two to shifts */
+#define HAVE_POF2OPT 1
+
+#define HAVE_WANTBNE 1
diff --git a/machines/bi386/machine.c b/machines/bi386/machine.c
new file mode 100755
index 0000000..37fe7a1
--- /dev/null
+++ b/machines/bi386/machine.c
@@ -0,0 +1,1446 @@
+/* Code generator for Intel 80386 or higher. */
+
+#include "supp.h"
+
+/* Was gehoert hier hin? */
+#define N_SO 128
+#define N_LSYM 128
+#define N_FUN 36
+#define N_PSYM 128
+
+static char FILE_[]=__FILE__;
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for i386/BE V0.1 (c) in 1997 by Volker Barthelmann";
+
+/* Commandline-flags the code-generator accepts */
+int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,
+ 0,0,0,0,
+ 0};
+char *g_flags_name[MAXGF]={"cpu","fpu","no-delayed-popping","const-in-data",
+ "merge-constants","elf","longalign","use-framepointer",
+ "g"};
+union ppi g_flags_val[MAXGF];
+
+/* Alignment-requirements for all types in bytes. */
+zlong align[16];
+
+/* Alignment that is sufficient for every object. */
+zlong maxalign;
+
+/* CHAR_BIT of the target machine. */
+zlong char_bit;
+
+/* Sizes of all elementary types in bytes. */
+zlong sizetab[16];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zlong t_min[32];
+zulong t_max[32];
+
+/* Names of all registers. */
+char *regnames[MAXR+1]={"noreg","%eax","%ecx","%edx","%ebx",
+ "%esi","%edi","%ebp","%esp",
+ "%st(0)","%st(1)","%st(2)","%st(3)",
+ "%st(4)","%st(5)","%st(6)","%st(7)"};
+
+/* The Size of each register in bytes. */
+zlong regsize[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1]={0,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1};
+
+
+/****************************************/
+/* Some private data and functions. */
+/****************************************/
+
+static long malign[16]={1,1,2,2,2,2,2,2,2,2,2,2,2,2,2};
+static long msizetab[16]={0,1,2,4,4,4,8,0,4,0,0,0,4,0};
+
+
+#define DATA 0
+#define BSS 1
+#define CODE 2
+
+static int section=-1,newobj;
+static char *codename="\t.text\n",*dataname="\t.data\n",*bssname="";
+static int is_const(struct Typ *);
+static const int ax=1,cx=2,dx=3,bx=4,si=5,di=6,bp=7,sp=8;
+static char x_t[]={'?','b','w','l','l','s','l','v','l','a','s','u','e','f','?','?'};
+static int is_const(struct Typ *);
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+
+static long loff,stackoffset,notpopped,dontpop;
+
+static char *ccs[]={"z","nz","l","ge","le","g","mp"};
+static char *ccu[]={"z","nz","b","ae","be","a","mp"};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"sal","sar","add","sub","imul","div","mod"};
+static char *farithmetics[]={"f?","f?","fadd","fsub","fmul","fdiv","fsubr","fdivr"};
+static char *dct[]={"","byte","short","long","long","long","long","long","long"};
+static pushedsize,pushorder=2;
+static int fst[8];
+static int cxl,dil,sil;
+static char *idprefix="_",*labprefix="l";
+
+static struct fpconstlist {
+ struct fpconstlist *next;
+ int label,typ;
+ union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+ struct fpconstlist *p=firstfpc;
+ t&=NQ;
+ if(g_flags[4]&USEDFLAG){
+ for(p=firstfpc;p;p=p->next){
+ if(t==p->typ){
+ eval_const(&p->val,t);
+ if(t==FLOAT&&zdeqto(vdouble,zf2zd(o->val.vfloat))) return(p->label);
+ if(t==DOUBLE&&zdeqto(vdouble,o->val.vdouble)) return(p->label);
+ }
+ }
+ }
+ p=mymalloc(sizeof(struct fpconstlist));
+ p->next=firstfpc;
+ p->label=++label;
+ p->typ=t;
+ p->val=o->val;
+ firstfpc=p;
+ return(p->label);
+}
+
+void title(FILE *f)
+{
+ static int done;
+ extern char *inname; /*grmpf*/
+ if(!done&&f){
+ done=1;
+ emit(f,"\t.file\t\"%s\"\n",inname);
+ }
+}
+
+static void probj2(FILE *f,struct obj *p,int t)
+/* Gibt Objekt auf Bildschirm aus */
+{
+ if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) fprintf(f,"(");
+ if(p->flags&VARADR) fprintf(f,"$");
+ if((p->flags&VAR)&&!(p->flags®)) {
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+ if(p->v->offset<0) fprintf(f,"%ld(%%esp)",(long)(loff-zl2l(p->v->offset)+zl2l(p->val.vlong))-stackoffset+pushedsize);
+ else fprintf(f,"%ld(%%esp)",(long)(zl2l(p->v->offset)+zl2l(p->val.vlong)-stackoffset));
+ }else{
+ if(!zleqto(l2zl(0L),p->val.vlong)){printval(f,&p->val,LONG,0);fprintf(f,"+");}
+ if(p->v->storage_class==STATIC&&(p->v->vtyp->flags&NQ)!=FUNKT){
+ fprintf(f,"%s%ld",labprefix,zl2l(p->v->offset));
+ }else{
+ fprintf(f,"%s%s",idprefix,p->v->identifier);
+ }
+ }
+ }
+ if(p->flags®){
+ if(p->reg>8){
+ int i;
+ for(i=0;i<8;i++){
+ if(fst[i]==p->reg)
+ fprintf(f,"%s",regnames[i+9]);
+ }
+ }else{
+ fprintf(f,"%s",regnames[p->reg]);
+ }
+ }
+ if(p->flags&KONST){
+ if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+ fprintf(f,"%s%d",labprefix,addfpconst(p,t));
+ }else{
+ fprintf(f,"$");printval(f,&p->val,t&NU,0);
+ }
+ }
+ if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) fprintf(f,")");
+}
+static void fxch(FILE *f,int i)
+{
+ int m;
+ fprintf(f,"\tfxch\t%s\n",regnames[i+9]);
+ m=fst[0];fst[0]=fst[i];fst[i]=m;
+}
+static int freest(void)
+{
+ int i;
+ for(i=0;i<8;i++){
+ if(fst[i]<0) return(i);
+ }
+ for(i=0;i<8;i++){
+ if(fst[i]==0) return(i);
+ }
+ ierror(0);
+}
+static void fpush(FILE *f)
+{
+ int i;
+ if(fst[7]>0){
+ i=freest();
+ if(fst[i]==0) fprintf(f,"\tffree\t%s\n",regnames[i+9]);
+ fxch(f,i);fxch(f,7);
+ }
+ for(i=7;i>0;i--)
+ fst[i]=fst[i-1];
+ fst[0]=-1;
+}
+static void fpop(void)
+{
+ int i;
+/* if(fst[0]>0&®s[fst[0]]) ierror(0);*/
+ for(i=0;i<7;i++)
+ fst[i]=fst[i+1];
+ fst[7]=-1;
+}
+static void fload(FILE *f,struct obj *o,int t)
+{
+ fprintf(f,"\tfld");
+ if((o->flags&(REG|DREFOBJ))==REG) fprintf(f,"\t");
+ else fprintf(f,"%c\t",x_t[t&NQ]);
+ probj2(f,o,t);fprintf(f,"\n");
+ fpush(f);
+}
+static void fstore(FILE *f,struct obj *o,int t)
+{
+ int i;
+ if((o->flags&(REG|DREFOBJ))==REG){
+ for(i=0;i<8;i++)
+ if(fst[i]==o->reg) fst[i]=-1;
+ fst[0]=o->reg;
+ }else{
+ fprintf(f,"\tfstp%c\t",x_t[t&NQ]);probj2(f,o,t);
+ fpop();fprintf(f,"\n");
+ }
+}
+static void prfst(FILE *f,char *s)
+{
+ int i;
+ if(DEBUG==0) return;
+ fprintf(f,"*\t%s\t",s);
+ for(i=0;i<8;i++){
+ if(fst[i]>=0){
+ if(fst[i]==0) fprintf(f,"+++ ");
+ else fprintf(f,"%s ",regnames[fst[i]]+3);
+ }else{
+ fprintf(f,"--- ");
+ }
+ }
+ fprintf(f,"\n");
+}
+static void finit(void)
+{
+ int i;
+ for(i=0;i<8;i++){
+ if(regs[i+9])
+ fst[i]=i+9;
+ else
+ fst[i]=-1;
+ }
+}
+static void forder(FILE *f)
+{
+ int i,m,unordered;
+ prfst(f,"forder");
+ for(i=0;i<8;i++){
+ if(fst[i]==0){fprintf(f,"\tffree\t%s\n",regnames[i+9]);fst[i]=-1;}
+ }
+oloop:
+ unordered=0;
+ for(i=0;i<8;i++){
+ if(fst[i]>0&&fst[i]!=i+9&®s[fst[i]]){unordered=1;break;}
+ }
+ if(!unordered) return;
+ if(fst[0]>=0&®s[fst[0]]){
+ if(fst[0]!=9){
+ fxch(f,fst[0]-9);
+ goto oloop;
+ }else{
+ fxch(f,freest());
+ }
+ }
+ for(i=1;i<8;i++){
+ if(fst[i]>=0&&fst[i]!=i+9&®s[fst[i]]&&fst[i]!=9){
+ fxch(f,i);
+ goto oloop;
+ }
+ }
+ if(regs[9]){
+ for(i=1;i<8;i++){
+ if(fst[i]==9){ fxch(f,i);return;}
+ }
+ }
+}
+static void pr(FILE *f,struct IC *p)
+{
+ int i;
+ for(;pushorder>2;pushorder>>=1){
+ for(i=1;i<=8;i++){
+ if(regs[i]&pushorder){
+ fprintf(f,"\tpopl\t%s\n",regnames[i]);
+ stackoffset+=4;regs[i]&=~pushorder;
+ }
+ }
+ }
+ for(i=1;i<=8;i++)
+ if(regs[i]&2) regs[i]&=~2;
+}
+
+/*ADA*/
+static int local_debug_line_count;
+static int local_debug_func_count;
+static char * debug_offset_func = NULL;
+
+static void emitdebugline (FILE *f, int line)
+{
+ if(g_flags[8]&USEDFLAG){
+ if (debug_offset_func && line)
+ {
+ /*
+ Tell GDB that a new line starts here.
+
+ Format: 68,0,<line>,<offset>
+
+ <line> is the current line number
+ <offset> is the offset to the current function.
+ */
+ fprintf (f, ".stabn 68,0,%d,%sM%d-%s\n", line, labprefix, local_debug_line_count, debug_offset_func);
+ fprintf (f, "%sM%d:\n", labprefix, local_debug_line_count);
+ local_debug_line_count ++;
+ }
+ }
+}
+
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+static int next_free_typeid = 32;
+
+static void begin_file (FILE *f, char *name)
+{
+ char * ptr;
+ char path[PATH_MAX];
+ int len1, len2, t;
+
+ ptr = strrchr (name, '/');
+ if (!ptr)
+ ptr = name-1;
+
+ /* Filename without path */
+ fprintf (f, "\t.file\t\"%s\"\n", ptr+1);
+ fprintf (f, "\t.version\t\"01.01\"\n");
+
+ getcwd (path, sizeof(path));
+ strcat (path, "/");
+ if (ptr != name-1)
+ {
+ len1 = strlen(path);
+ len2 = ptr-name;
+ strncpy (path+len1, name, len2);
+ path[len1+len2] = 0;
+ strcat (path, "/");
+ }
+
+ /* Emit absolute path to source file and the filename with any
+ path the user gave to the frontend */
+ fprintf (f, "\t.stabs \"%s\",%d,0,0,%stext0\n", path, N_SO, labprefix);
+ fprintf (f, "\t.stabs \"%s\",%d,0,0,%stext0\n", name, N_SO, labprefix);
+ fprintf (f, ".text\n%stext0:\n",labprefix);
+ fprintf (f, "\t.stabs \"vbcc_compiled.\", 0x3c, 0, 0, 0\n");
+
+ /* Emit types. Format is:
+
+ "<name>:<t#1>=<r#2;min;max;>",128,0,0,0
+
+ 128,0,0,0 tells GDB this is a type definition
+ <name> is the name of the symbol.
+ <t#1> is the name of the type and its number
+ <r#2;min;max;> is a range. The min and max values are in the format
+ of the type #2. min and max values for this type can be
+ omitted.
+ void is defined by <t#1=#1>.
+ */
+ for (t=CHAR; t<=LONG; t++)
+ {
+ fprintf (f, ".stabs \"%s:t%d=r%d;%ld;%ld;\",%d,0,0,0\n", typname[t],t,t==CHAR ? CHAR:INT,
+ zl2l(t_min[t]),zl2l(t_max[t]),N_LSYM);
+ fprintf (f, ".stabs \"unsigned %s:t%d=r%d;%lu;%lu;\",%d,0,0,0\n", typname[t],
+ t|UNSIGNED, INT,
+ zul2ul(t_min[t|UNSIGNED]),zul2ul(t_max[t|UNSIGNED]), N_LSYM);
+ }
+
+ fprintf (f, ".stabs \"float:t%d=r%d;%ld;0;\",%d,0,0,0\n",
+ FLOAT,INT,zl2l(sizetab[FLOAT]),N_LSYM);
+ fprintf (f, ".stabs \"double:t%d=r%d;%ld;0;\",%d,0,0,0\n",
+ DOUBLE,INT,zl2l(sizetab[DOUBLE]),N_LSYM);
+ fprintf (f, ".stabs \"void:t%d=r%d\",%d,0,0,0\n",
+ VOID,VOID,N_LSYM);
+
+
+ /*
+ fprintf (f, ".stabs \"char:t2=r2;0;127;\",128,0,0,0\n");
+ fprintf (f, ".stabs \"int:t1=r1;-2147483648;2147483647;\",128,0,0,0\n");
+ fprintf (f, ".stabs \"long int:t3=r1;-2147483648;2147483647;\",128,0,0,0\n");
+ fprintf (f, ".stabs \"unsigned int:t4=r1;0;-1;\",128,0,0,0\n");
+ fprintf (f, ".stabs \"long unsigned int:t5=r1;0;-1;\",128,0,0,0\n");
+ fprintf (f, ".stabs \"void:t19=19\",128,0,0,0\n");
+ */
+}
+
+static void debug_print_stab_type (FILE *f, struct Typ *typ)
+{
+ int t = typ->flags & NU;
+
+ if (t <= VOID)
+ fprintf (f, "%d", t);
+ else if (t == ARRAY || t == POINTER)
+ {
+ fprintf (f, "%d=*", next_free_typeid++);
+ debug_print_stab_type (f, typ->next);
+ }
+ else
+ {
+ ierror(t);
+ }
+}
+
+
+static void function_top(FILE *f,struct Var *v,long offset)
+/* erzeugt Funktionskopf */
+{
+ int i;
+ struct struct_declaration *p;
+
+ if(section!=CODE){fprintf(f,codename);section=CODE;}
+
+ /*ADA*/
+ if(g_flags[8]&USEDFLAG){ /*vb*/
+ fprintf (f, "\t.align\t16\n");
+ /* Tell GDB that a new function starts here.
+
+ Format: "<name>:F<type>",36,0,<line>,<symname>
+
+ <name> Is the name of the function
+ <type> is the return type (only the number as defined above, ie.
+ if int is t1, then this is 1).
+ <line> The line in the source
+ <symname> The name of the symbol as it appears in the object file.
+
+ Right now, all functions return void.
+ */
+
+ fprintf (f, ".stabs \"%s:F", v->identifier);
+ debug_print_stab_type (f, v->vtyp->next);
+ fprintf (f, "\",%d,0,%d,%s%s\n", N_FUN, fline, idprefix,v->identifier);
+
+ p=v->vtyp->exact;
+ for (i=0; i<p->count; i++)
+ {
+ if((*p->sl)[i].styp->flags==VOID) break;
+ fprintf (f, ".stabs \"%s:p", (*p->sl)[i].identifier);
+ debug_print_stab_type (f, (*p->sl)[i].styp);
+ /* TODO i*4+4 is a crude method to find the offset of a parameter on
+ the stack */
+ fprintf (f, "\",%d,0,0,%d\n", N_PSYM, i*4+4);
+ }
+ }
+
+ if(v->storage_class==EXTERN) fprintf(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+ fprintf(f,"%s%s:\n",idprefix,v->identifier);
+
+ /*ADA*/
+ debug_offset_func=v->identifier;
+
+ for(pushedsize=0,i=1;i<sp;i++){
+ if(regused[i]&&!regscratch[i]){
+ fprintf(f,"\tpushl\t%s\n",regnames[i]);
+ pushedsize+=4;
+ }
+ }
+
+ if(offset) fprintf(f,"\tsubl\t$%ld,%%esp\n",offset);
+ if(g_flags[7]&USEDFLAG) fprintf(f,"\tmovl\t%s,%s\n",regnames[sp],regnames[7]);
+ if(g_flags[8]&USEDFLAG){
+ /* Tell GDB that the code of the function starts here */
+ emitdebugline (f,fline);
+ local_debug_func_count ++;
+ fprintf (f, "%sBB%d:\n", labprefix, local_debug_func_count);
+ }
+}
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/* erzeugt Funktionsende */
+{
+ int i;
+ forder(f);
+
+ if(g_flags[8]&USEDFLAG){
+ emitdebugline (f,fline);
+ fprintf (f, "%sBE%d:\n", labprefix, local_debug_func_count);
+ }
+
+ if(offset) fprintf(f,"\taddl\t$%ld,%%esp\n",offset);
+ for(i=sp-1;i>0;i--){
+ if(regused[i]&&!regscratch[i]){
+ fprintf(f,"\tpopl\t%s\n",regnames[i]);
+ }
+ }
+ fprintf(f,"\tret\n");
+
+ if(g_flags[8]&USEDFLAG){
+ fprintf (f, "%sfe%d:\n\t.size\t%s,%sfe%d-%s%s\n", labprefix, local_debug_func_count, v->identifier, labprefix, local_debug_func_count, idprefix,v->identifier);
+ /* Tell GDB the real size of the function */
+ fprintf (f, ".stabn 192,0,0,%sBB%d-%s%s\n",labprefix,local_debug_func_count, idprefix,v->identifier);
+ fprintf (f, ".stabn 224,0,0,%sBE%d-%s%s\n", labprefix, local_debug_func_count, idprefix,v->identifier);
+ }
+}
+static int is_const(struct Typ *t)
+/* Tests if a type can be placed in the code-section. */
+{
+ if(!(t->flags&(CONST|STRINGCONST))){
+ do{
+ if(t->flags&(CONST|STRINGCONST)) return(1);
+ if((t->flags&NQ)!=ARRAY) return(0);
+ t=t->next;
+ }while(1);
+ }else return(1);
+}
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+ if(o1->flags==o2->flags&&o1->am==o2->am){
+ if(!(o1->flags&VAR)||(o1->v==o2->v&&zleqto(o1->val.vlong,o2->val.vlong))){
+ if(!(o1->flags®)||o1->reg==o2->reg){
+ return(1);
+ }
+ }
+ }
+ return(0);
+}
+static int get_reg(FILE *f,struct IC *p)
+{
+ int i;
+ /* If we can use a register which was already used by the compiler */
+ /* or it is a sratch register then we can use it without problems. */
+ for(i=1;i<=8;i++){
+ if(!regs[i]&&(regused[i]||regscratch[i])){
+ regs[i]=2;
+ return(i);
+ }
+ }
+ /* Otherwise we have to save this register. */
+ /* We may not use a register which is used in this IC. */
+ for(i=1;i<=8;i++){
+ if(regs[i]<2
+ &&(!(p->q1.flags®)||p->q1.reg!=i)
+ &&(!(p->q2.flags®)||p->q2.reg!=i)
+ &&(!(p->z.flags®)||p->z.reg!=i) ){
+
+ fprintf(f,"\tpushl\t%s\n",regnames[i]);
+ /* Mark register as pushed (taking care of the order). */
+ pushorder<<=1; regs[i]|=pushorder;
+ stackoffset-=4;
+ return(i);
+ }
+ }
+ ierror(0);
+}
+static void move(FILE *f,struct obj *q,int qr,struct obj *z,int zr,int t)
+/* Generates code to move object q (or register qr) into object z (or */
+/* register zr). */
+{
+ if(q&&(q->flags&(REG|DREFOBJ))==REG) qr=q->reg;
+ if(z&&(z->flags&(REG|DREFOBJ))==REG) zr=z->reg;
+ if(qr&&zr){
+ if(qr!=zr)
+ fprintf(f,"\tmovl\t%s,%s\n",regnames[qr],regnames[zr]);
+ return;
+ }
+ if(zr&&(q->flags&KONST)){
+ eval_const(&q->val,t);
+ if(zleqto(vlong,l2zl(0L))&&zuleqto(vulong,ul2zul(0UL))&&zdeqto(vdouble,d2zd(0.0))){
+ fprintf(f,"\txorl\t%s,%s\n",regnames[zr],regnames[zr]);
+ return;
+ }
+ }
+ fprintf(f,"\tmov%c\t",x_t[t&NQ]);
+ if(qr) fprintf(f,"%s",regnames[qr]); else probj2(f,q,t);
+ fprintf(f,",");
+ if(zr) fprintf(f,"%s",regnames[zr]); else probj2(f,z,t);
+ fprintf(f,"\n");
+}
+static long pof2(zulong x)
+/* Yields log2(x)+1 oder 0. */
+{
+ zulong p;int ln=1;
+ p=ul2zul(1L);
+ while(zulleq(p,x)){
+ if(zuleqto(x,p)) return(ln);
+ ln++;p=zuladd(p,p);
+ }
+ return(0);
+}
+
+/****************************************/
+/* End of private fata and functions. */
+/****************************************/
+
+
+int init_cg(void)
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+{
+ int i;
+
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zl(4L);
+ char_bit=l2zl(8L);
+ if(g_flags[6]&USEDFLAG){
+ for(i=SHORT;i<16;i++) malign[i]=4;
+ }
+ for(i=0;i<16;i++){
+ sizetab[i]=l2zl(msizetab[i]);
+ align[i]=l2zl(malign[i]);
+ }
+ for(i=1;i<= 8;i++) regsize[i]=l2zl(4L);
+ for(i=9;i<=16;i++) regsize[i]=l2zl(8L);
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[UNSIGNED|CHAR]=t_min[UNSIGNED|SHORT]=t_min[UNSIGNED|INT]=t_min[UNSIGNED|LONG]=l2zl(0L);
+ t_min[CHAR]=l2zl(-128L);
+ t_min[SHORT]=l2zl(-32768L);
+ t_min[LONG]=zlsub(l2zl(-2147483647L),l2zl(1L));
+ t_min[INT]=t_min[LONG];
+ t_max[CHAR]=ul2zul(127L);
+ t_max[SHORT]=ul2zul(32767UL);
+ t_max[LONG]=ul2zul(2147483647UL);
+ t_max[INT]=t_max[LONG];
+ t_max[UNSIGNED|CHAR]=ul2zul(255UL);
+ t_max[UNSIGNED|SHORT]=ul2zul(65535UL);
+ t_max[UNSIGNED|LONG]=ul2zul(4294967295UL);
+ t_max[UNSIGNED|INT]=t_max[UNSIGNED|LONG];
+ /* Reserve a few registers for use by the code-generator. */
+ /* We only reserve the stack-pointer here. */
+ regsa[sp]=1;
+ /* If we are to use a framepointer also reserve %ebp. */
+ if(g_flags[7]&USEDFLAG) regsa[7]=1;
+ /* We need at least one free slot in the flaoting point stack */
+ regsa[16]=1;regscratch[16]=0;
+ /* Use l%d as labels and _%s as identifiers by default. If */
+ /* -elf is specified we use .l%d and %s instead. */
+ if(g_flags[5]&USEDFLAG) {labprefix=".L";idprefix="";}
+ return(1);
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+{
+ if((t->flags&NQ)==FLOAT||(t->flags&NQ)==DOUBLE) return 9;
+ if((t->flags&NQ)<=POINTER) return 1;
+ return 0;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(r==0) return(0);
+ t&=NQ;
+ if(r>8){
+ if(t==FLOAT||t==DOUBLE) return(1);
+ else return(0);
+ }
+ if(t==CHAR&&(r==si||r==di||r==bp)) return(0);
+ if(t<=LONG) return(1);
+ if(t==POINTER) return(1);
+ return(0);
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return(0);
+ if((c==DIV||c==MOD)&&!(p->q2.flags&KONST))
+ return(1);
+ return(0);
+}
+
+int must_convert(np p,int t)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* In this generic 32bit RISC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int o=p->ntyp->flags,op=o&NQ,tp=t&NQ;
+ if(tp==POINTER&&op==POINTER) return(0);
+ if((t&UNSIGNED)&&(o&UNSIGNED)&&zleqto(sizetab[tp],sizetab[op])) return(0);
+ if((tp==INT&&op==LONG)||(tp==LONG&&op==INT)) return(0);
+
+ return(1);
+}
+
+void gen_ds(FILE *f,zlong size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ title(f);
+ if(newobj) fprintf(f,"%ld\n",zl2l(size));
+ else fprintf(f,"\t.space\t%ld\n",zl2l(size));
+ newobj=0;
+}
+
+void gen_align(FILE *f,zlong align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ title(f);
+ if(!zlleq(align,l2zl(1L))) fprintf(f,"\t.align\t2\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;
+ title(f);
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if((v->vtyp->flags&NQ)==FUNKT) return;
+ if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&§ion!=DATA){fprintf(f,dataname);section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&§ion!=CODE){fprintf(f,codename);section=CODE;}
+ if(!v->clist&§ion!=BSS){fprintf(f,bssname);section=BSS;}
+ if(section!=BSS) fprintf(f,"\t.align\t2\n%s%ld:\n",labprefix,zl2l(v->offset));
+ else fprintf(f,"\t.lcomm\t%s%ld,",labprefix,zl2l(v->offset));
+ newobj=1;
+ }
+ if(v->storage_class==EXTERN){
+ fprintf(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+ if(v->flags&(DEFINED|TENTATIVE)){
+ if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&§ion!=DATA){fprintf(f,dataname);section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&§ion!=CODE){fprintf(f,codename);section=CODE;}
+ if(!v->clist&§ion!=BSS){fprintf(f,bssname);section=BSS;}
+ if(section!=BSS) fprintf(f,"\t.align\t2\n%s%s:\n",idprefix,v->identifier);
+ else fprintf(f,"\t.comm\t%s%s,",idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ title(f);
+ fprintf(f,"\t.%s\t",dct[t&NQ]);
+ if(!p->tree){
+ if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+ ip=(unsigned char *)&p->val.vdouble;
+ fprintf(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+ if((t&NQ)==DOUBLE){
+ fprintf(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+ }
+ }else{
+ printval(f,&p->val,t&NU,0);
+ }
+ }else{
+ int m=p->tree->o.flags;
+ p->tree->o.flags&=~VARADR;
+ probj2(f,&p->tree->o,t&NU);
+ p->tree->o.flags=m;
+ }
+ fprintf(f,"\n");newobj=0;
+}
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+void gen_code(FILE *f,struct IC *p,struct Var *v,zlong offset)
+{
+ int c,t,lastcomp=0,reg;
+ int lastline=-1;
+
+ if(DEBUG&1) printf("gen_code()\n");
+ for(c=1;c<=15;c++) regs[c]=regsa[c];
+ regs[16]=0;
+ loff=((zl2l(offset)+1)/2)*2;
+ title(f);
+ function_top(f,v,loff);
+ stackoffset=notpopped=dontpop=0;
+ finit();
+ for(;p;pr(f,p),p=p->next){
+ c=p->code;t=p->typf;
+ if(c==NOP) continue;
+
+/*ADA*/
+if (lastline != p->line)
+{
+ emitdebugline(f,p->line);
+ lastline = p->line;
+}
+
+ if(c==SUBPFP) c=SUB;
+ if(c==SUBIFP) c=SUB;
+ if(c==ADDI2P) c=ADD;
+ if(c==ALLOCREG){
+ regs[p->q1.reg]=1;
+ continue;
+ }
+ if(c==FREEREG){
+ if(p->q1.reg>=9){
+ for(c=0;c<8;c++)
+ if(fst[c]==p->q1.reg) fst[c]=0;
+ }
+ regs[p->q1.reg]=0;
+ continue;
+ }
+ if(notpopped&&!dontpop){
+ int flag=0;
+ if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+ fprintf(f,"\taddl\t$%ld,%%esp\n",notpopped);
+ stackoffset+=notpopped;notpopped=0;
+ }
+ }
+ if(c==LABEL) {forder(f);fprintf(f,"%s%d:\n",labprefix,t);continue;}
+ if(c>=BEQ&&c<=BRA){
+ forder(f);
+ if(lastcomp&UNSIGNED) fprintf(f,"\tj%s\t%s%d\n",ccu[c-BEQ],labprefix,t);
+ else fprintf(f,"\tj%s\t%s%d\n",ccs[c-BEQ],labprefix,t);
+ continue;
+ }
+ if(c==MOVETOREG){
+ if(p->z.reg>8){
+ for(c=0;c<8;c++){
+ if(fst[c]==p->z.reg) fst[c]=0;
+ }
+ fload(f,&p->q1,DOUBLE);
+ fst[0]=p->z.reg;
+ continue;
+ }
+ move(f,&p->q1,0,0,p->z.reg,LONG);
+ continue;
+ }
+ if(c==MOVEFROMREG){
+ if(p->q1.reg>8){
+ if(fst[0]!=p->q1.reg){
+ for(c=0,reg=-1;c<8;c++){
+ if(fst[c]==p->q1.reg) reg=c;
+ }
+ if(reg<0) ierror(0);
+ fxch(f,reg);
+ }
+ fprintf(f,"\tfstpl\t");probj2(f,&p->z,DOUBLE);
+ fprintf(f,"\n");fpop();
+ continue;
+ }
+ move(f,0,p->q1.reg,&p->z,0,LONG);
+ continue;
+ }
+ if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ){
+ reg=get_reg(f,p);
+ move(f,&p->q1,0,0,reg,LONG);
+ p->q1.flags|=REG;p->q1.reg=reg;
+ }
+ if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ){
+ reg=get_reg(f,p);
+ move(f,&p->q2,0,0,reg,LONG);
+ p->q2.flags|=REG;p->q2.reg=reg;
+ }
+ if((p->z.flags&(DREFOBJ|REG))==DREFOBJ){
+ reg=get_reg(f,p);
+ move(f,&p->z,0,0,reg,LONG);
+ p->z.flags|=REG;p->z.reg=reg;
+ }
+ if(c>=CONVCHAR&&c<=CONVULONG){
+ int to;
+ if(c==CONVCHAR) to=CHAR;
+ if(c==CONVUCHAR) to=(UNSIGNED|CHAR);
+ if(c==CONVSHORT) to=SHORT;
+ if(c==CONVUSHORT) to=(UNSIGNED|SHORT);
+ if(c==CONVINT) to=INT;
+ if(c==CONVUINT) to=(UNSIGNED|INT);
+ if(c==CONVLONG) to=INT;
+ if(c==CONVULONG) to=(UNSIGNED|INT);
+ if(c==CONVFLOAT) to=FLOAT;
+ if(c==CONVDOUBLE) to=DOUBLE;
+ if(c==CONVPOINTER) to=(UNSIGNED|INT);
+ if((t&NU)==LONG) t=INT;
+ if((t&NU)==(UNSIGNED|LONG)||(t&NU)==POINTER) t=(UNSIGNED|INT);
+ if((to&NQ)<=INT&&(t&NQ)<=INT){
+ if(isreg(z)) reg=p->z.reg;
+ else if(isreg(q1)) reg=p->q1.reg;
+ else reg=get_reg(f,p);
+ if((to&NQ)<=SHORT){
+ fprintf(f,"\tmov%c%cl\t",(to&UNSIGNED)?'z':'s',x_t[to&NQ]);
+ if(isreg(q1)){
+ if((to&NQ)==SHORT){
+ fprintf(f,"%%%s",regnames[p->q1.reg]+2);
+ }else{
+ fprintf(f,"%%%cl",regnames[p->q1.reg][2]);
+ }
+ }else probj2(f,&p->q1,to);
+ fprintf(f,",%s\n",regnames[reg]);
+ }else{
+ move(f,&p->q1,0,0,reg,to);
+ }
+ move(f,0,reg,&p->z,0,t);
+ continue;
+ }
+ if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+ if((to&NQ)==FLOAT||(to&NQ)==DOUBLE){
+ if(isreg(q1)&&fst[0]==p->q1.reg){
+ if(isreg(z)){
+ if(p->z.reg==fst[0]) continue;
+ for(reg=0,c=7;c>=0;c--){
+ if(fst[c]==p->z.reg){reg=c;break;}
+ if(fst[c]<0) reg=c;
+ }
+ fst[reg]=p->z.reg;
+ }
+ fprintf(f,"\tfst%c\t",x_t[t&NQ]);
+ probj2(f,&p->z,t);fprintf(f,"\n");
+ continue;
+ }
+ fload(f,&p->q1,to);
+ fstore(f,&p->z,t);
+ continue;
+ }
+ if((to&NQ)<=SHORT){
+ if(isreg(q1)){
+ reg=p->q1.reg;
+ if(to&UNSIGNED){
+ fprintf(f,"\tandl\t$%ld,%s\n",(to&NQ)==CHAR?255L:65535L,regnames[reg]);
+ }else{
+/* fprintf(f,"\tc%ctl\t%s\n",x_t[to&NQ],regnames[reg]);*/
+ if((to&NQ)==SHORT){
+ fprintf(f,"\tmovswl\t%%%s,%s\n",regnames[reg]+2,regnames[reg]);
+ }else{
+ fprintf(f,"\tmovsbl\t%%%cl,%s\n",regnames[reg][2],regnames[reg]);
+ }
+ }
+ }else{
+ reg=get_reg(f,p);
+ if(to&UNSIGNED){
+ fprintf(f,"\tmovz%cl\t",x_t[to&NQ]);
+ }else{
+ fprintf(f,"\tmovs%cl\t",x_t[to&NQ]);
+ }
+ probj2(f,&p->q1,to);fprintf(f,",%s\n",regnames[reg]);
+ }
+ fprintf(f,"\tpushl\t%s\n",regnames[reg]);
+ fprintf(f,"\tfildl\t(%s)\n\taddl\t$4,%s\n",regnames[sp],regnames[sp]);
+ }else{
+ if(to&UNSIGNED){
+ fprintf(f,"\tpushl\t$0\n\tpushl\t");stackoffset-=4;
+ probj2(f,&p->q1,to);
+ fprintf(f,"\n\tfildq\t(%s)\n\taddl\t$8,%s\n",regnames[sp],regnames[sp]);
+ stackoffset+=4;
+ }else{
+ if(isreg(q1)){
+ fprintf(f,"\tpushl\t%s\n\tfildl\t(%s)\n\taddl\t$4,%s\n",regnames[p->q1.reg],regnames[sp],regnames[sp]);
+ }else{
+ fprintf(f,"\tfildl\t");probj2(f,&p->q1,t);
+ fprintf(f,"\n");
+ }
+ }
+ }
+ fpush(f);
+ fstore(f,&p->z,t);
+ continue;
+ }
+ if((to&NQ)==FLOAT||(to&NQ)==DOUBLE){
+ if(isreg(q1)&&fst[0]==p->q1.reg){
+ if((t&NQ)==CHAR){
+ if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p);
+ fprintf(f,"\tsubl\t$4,%s\n\tfistl\t(%s)\n\tmovsbl\t(%s),%s\n\taddl\t$4,%s\n",regnames[sp],regnames[sp],regnames[sp],regnames[reg],regnames[sp]);
+ move(f,0,reg,&p->z,0,t);
+ }else{
+ if(isreg(z)){
+ fprintf(f,"\tsubl\t$4,%s\n\tfistl\t(%s)\n\tmov%c\t(%s),",regnames[sp],regnames[sp],x_t[t&NQ],regnames[sp]);
+ stackoffset-=4;
+ probj2(f,&p->z,t);fprintf(f,"\n\taddl\t$4,%s\n",regnames[sp]);
+ stackoffset+=4;
+ }else{
+ fprintf(f,"\tfist%c\t",x_t[t&NQ]);
+ probj2(f,&p->z,t);fprintf(f,"\n");
+ }
+ }
+ }else{
+ fload(f,&p->q1,to);
+ if((t&NQ)==CHAR){
+ if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p);
+ fprintf(f,"\tsubl\t$4,%s\n\tfistpl\t(%s)\n\tmovsbl\t(%s),%s\n\taddl\t$4,%s\n",regnames[sp],regnames[sp],regnames[sp],regnames[reg],regnames[sp]);
+ fpop(); move(f,0,reg,&p->z,0,t);
+ }else{
+ if(isreg(z)){
+ fprintf(f,"\tsubl\t$4,%s\n\tfistpl\t(%s)\n\tmov%c\t(%s),",regnames[sp],regnames[sp],x_t[t&NQ],regnames[sp]);
+ stackoffset-=4;
+ probj2(f,&p->z,t);fprintf(f,"\n\taddl\t$4,%s\n",regnames[sp]);
+ stackoffset+=4;fpop();
+ }else{
+ fprintf(f,"\tfistp%c\t",x_t[t&NQ]);
+ probj2(f,&p->z,t);fprintf(f,"\n");fpop();
+ }
+ }
+ }
+ continue;
+ }
+ ierror(0);
+ }
+ if(c==MINUS||c==KOMPLEMENT){
+ char *s;
+ if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+ if(isreg(z)&&p->z.reg==9&&isreg(q1)&&p->q1.reg==9){
+ fprintf(f,"\tfchs\n");
+ continue;
+ }
+ fload(f,&p->q1,t);
+ fprintf(f,"\tfchs\n");
+ fprintf(f,"\tfstp%c\t",x_t[t&NQ]);
+ probj2(f,&p->z,t);fprintf(f,"\n");
+ fpop();
+ continue;
+ }
+ if(c==MINUS) s="neg"; else s="not";
+ if(compare_objects(&p->q1,&p->q2)){
+ fprintf(f,"\t%s%c\t",s,x_t[t&NQ]);
+ probj2(f,&p->z,t);fprintf(f,"\n");
+ continue;
+ }
+ if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p);
+ move(f,&p->q1,0,0,reg,t);
+ fprintf(f,"\t%s%c\t%s\n",s,x_t[t&NQ],regnames[reg]);
+ move(f,0,reg,&p->z,0,t);
+ continue;
+ }
+ if(c==SETRETURN){
+ if(p->z.reg){
+ if(p->z.reg==9){
+ if(!isreg(q1)||fst[0]!=p->q1.reg)
+ fload(f,&p->q1,t);
+ }else{
+ move(f,&p->q1,0,0,p->z.reg,t);
+ }
+ }
+ continue;
+ }
+ if(c==GETRETURN){
+ if(p->q1.reg){
+ if(p->q1.reg==9){
+ if(!isreg(z)||fst[0]!=p->z.reg)
+ fstore(f,&p->z,t);
+ }else{
+ move(f,0,p->q1.reg,&p->z,0,t);
+ }
+ }
+ continue;
+ }
+ if(c==CALL){
+ int reg;
+ if(p->q1.flags&DREFOBJ){
+ if(!(p->q1.flags®)) ierror(0);
+ fprintf(f,"\tcall\t*%s\n",regnames[p->q1.reg]);
+ }else{
+ fprintf(f,"\tcall\t");probj2(f,&p->q1,t);
+ fprintf(f,"\n");
+ }
+ if(!zleqto(l2zl(0L),p->q2.val.vlong)){
+ notpopped+=zl2l(p->q2.val.vlong);
+ dontpop-=zl2l(p->q2.val.vlong);
+ if(!(g_flags[2]&USEDFLAG)&&stackoffset==-notpopped){
+ /* Entfernen der Parameter verzoegern */
+ }else{
+ fprintf(f,"\taddl\t$%ld,%%esp\n",zl2l(p->q2.val.vlong));
+ stackoffset+=zl2l(p->q2.val.vlong);
+ notpopped-=zl2l(p->q2.val.vlong);
+ }
+ }
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(c==PUSH) dontpop+=zl2l(p->q2.val.vlong);
+ if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+ if(c==ASSIGN){
+ prfst(f,"fassign");
+ fload(f,&p->q1,t);
+ fstore(f,&p->z,t);
+ continue;
+ }else if(isreg(q1)){
+ prfst(f,"fpush");
+ fprintf(f,"\tsubl\t$%ld,%s\n",zl2l(sizetab[t&NQ]),regnames[sp]);
+ stackoffset-=zl2l(sizetab[t&NQ]);
+ if(fst[0]==p->q1.reg){
+ fprintf(f,"\tfst%c\t(%s)\n",x_t[t&NQ],regnames[sp]);
+ }else{
+ fload(f,&p->q1,t);
+ fprintf(f,"\tfstp%c\t(%s)\n",x_t[t&NQ],regnames[sp]);
+ fpop();
+ }
+ continue;
+ }
+ }
+ if((t&NQ)>POINTER||!zleqto(p->q2.val.vlong,sizetab[t&NQ])||!zlleq(p->q2.val.vlong,l2zl(4L))){
+ int mdi=di,msi=si,m=0;long l;
+ l=zl2l(p->q2.val.vlong);
+ if(regs[cx]){m|=1;if(!cxl)cxl=++label;fprintf(f,"\tmovl\t%s,%s%d\n",regnames[cx],labprefix,cxl);}
+ if(regs[msi]||!regused[msi]){m|=2;if(!sil)sil=++label;fprintf(f,"\tmovl\t%s,%s%d\n",regnames[msi],labprefix,sil);}
+ if(regs[mdi]||!regused[mdi]){m|=4;if(!dil)dil=++label;fprintf(f,"\tmovl\t%s,%s%d\n",regnames[mdi],labprefix,dil);}
+ if((p->z.flags®)&&p->z.reg==msi&&(p->q1.flags®)&&p->q1.reg==mdi){
+ msi=di;mdi=si;
+ m|=8;
+ }
+ if(!(p->z.flags®)||p->z.reg!=msi){
+ fprintf(f,"\tleal\t");probj2(f,&p->q1,t);
+ fprintf(f,",%s\n",regnames[msi]);
+ }
+ if(c==PUSH){
+ fprintf(f,"\tsubl\t$%ld,%s\n\tmovl\t%s,%s\n",l,regnames[sp],regnames[sp],regnames[mdi]);
+ stackoffset-=l;
+ }else{
+ fprintf(f,"\tleal\t");probj2(f,&p->z,t);
+ fprintf(f,",%s\n",regnames[mdi]);
+ }
+ if((p->z.flags®)&&p->z.reg==msi){
+ fprintf(f,"\tleal\t");probj2(f,&p->q1,t);
+ fprintf(f,",%s\n",regnames[msi]);
+ }
+ if(m&8){
+ msi=si;mdi=di;
+ fprintf(f,"\txch\t%s,%s\n",regnames[msi],regnames[mdi]);
+ }
+ if((t&NQ)==ARRAY||(t&NQ)==CHAR||l<4){
+ fprintf(f,"\tmovl\t$%ld,%s\n\trep\n\tmovsb\n",l,regnames[cx]);
+ }else{
+ if(l>=8)
+ fprintf(f,"\tmovl\t$%ld,%s\n\trep\n",l/4,regnames[cx]);
+ fprintf(f,"\tmovsl\n");
+ if(l%2) fprintf(f,"\tmovsw\n");
+ if(l%1) fprintf(f,"\tmovsb\n");
+ }
+ if(m&4) fprintf(f,"\tmovl\t%s%d,%s\n",labprefix,dil,regnames[mdi]);
+ if(m&2) fprintf(f,"\tmovl\t%s%d,%s\n",labprefix,sil,regnames[msi]);
+ if(m&1) fprintf(f,"\tmovl\t%s%d,%s\n",labprefix,cxl,regnames[cx]);
+ continue;
+ }
+ if(t==FLOAT) t=LONG;
+ if(c==PUSH){
+ fprintf(f,"\tpush%c\t",x_t[t&NQ]);
+ probj2(f,&p->q1,t);fprintf(f,"\n");
+ stackoffset-=zl2l(p->q2.val.vlong);
+ continue;
+ }
+ if(c==ASSIGN){
+ if(p->q1.flags&KONST){
+ move(f,&p->q1,0,&p->z,0,t);
+ continue;
+ }
+ if(isreg(z)) reg=p->z.reg;
+ else if(isreg(q1)) reg=p->q1.reg;
+ else reg=get_reg(f,p);
+ move(f,&p->q1,0,0,reg,t);
+ move(f,0,reg,&p->z,0,t);
+ continue;
+ }
+ ierror(0);
+ }
+ if(c==ADDRESS){
+ if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p);
+ fprintf(f,"\tleal\t");probj2(f,&p->q1,t);
+ fprintf(f,",%s\n",regnames[reg]);
+ move(f,0,reg,&p->z,0,POINTER);
+ continue;
+ }
+ if(c==TEST){
+ lastcomp=t;
+ if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+ if(isreg(q1)&&fst[0]==p->q1.reg){
+ fprintf(f,"\tftst\n");lastcomp|=UNSIGNED;
+ continue;
+ }else{
+ p->code=c=COMPARE;
+ p->q2.flags=KONST;
+ p->q2.val.vdouble=d2zd(0.0);
+ if((t&NQ)==FLOAT) p->q2.val.vfloat=zd2zf(p->q2.val.vdouble);
+ /* fall through to COMPARE */
+ }
+ }else{
+ fprintf(f,"\tcmp%c\t$0,",x_t[t&NQ]);
+ probj2(f,&p->q1,t);fprintf(f,"\n");
+ continue;
+ }
+ }
+ if(c==COMPARE){
+ lastcomp=t;
+ if(isreg(q2)||(p->q1.flags&KONST)){
+ struct IC *b=p->next;
+ struct obj o;
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ while(b&&b->code==FREEREG) b=b->next;
+ if(!b) ierror(0);
+ if(b->code==BLT) b->code=BGT;
+ else if(b->code==BLE) b->code=BGE;
+ else if(b->code==BGT) b->code=BLT;
+ else if(b->code==BGE) b->code=BLE;
+ }
+ if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+ prfst(f,"fcomp");
+ if(isreg(q1)&&p->q1.reg==fst[0]){
+ fprintf(f,"\tfcom%c\t",x_t[t&NQ]);
+ probj2(f,&p->q2,t);fprintf(f,"\n");
+ }else{
+ fload(f,&p->q1,t);
+ fprintf(f,"\tfcomp%c\t",x_t[t&NQ]);
+ probj2(f,&p->q2,t);fprintf(f,"\n");
+ fpop();
+ }
+ fprintf(f,"\tfstsw\n\tsahf\n");
+ lastcomp|=UNSIGNED;
+ continue;
+ }
+ if(!isreg(q1)){
+ if(!isreg(q2)){
+ reg=get_reg(f,p);
+ move(f,&p->q1,0,0,reg,t);
+ p->q1.flags=REG;
+ p->q1.reg=reg;
+ }
+ }
+ fprintf(f,"\tcmp%c\t",x_t[t&NQ]);
+ probj2(f,&p->q2,t);fprintf(f,",");
+ probj2(f,&p->q1,t);fprintf(f,"\n");
+ continue;
+ }
+ if((t&NQ)==FLOAT||(t&NQ)==DOUBLE){
+ char s[2];
+ prfst(f,"fmath");
+ if(isreg(q2)) s[0]=0; else {s[0]=x_t[t&NQ];s[1]=0;}
+ if(isreg(z)&&isreg(q1)&&p->q1.reg==fst[0]&&p->z.reg==fst[0]){
+ fprintf(f,"\t%s%s\t",farithmetics[c-LSHIFT],s);
+ probj2(f,&p->q2,t); fprintf(f,"\n");continue;
+ }
+ fload(f,&p->q1,t);
+ fprintf(f,"\t%s%s\t",farithmetics[c-LSHIFT],s);
+ probj2(f,&p->q2,t); fprintf(f,"\n");
+ fstore(f,&p->z,t); continue;
+ }
+ if((c==MULT||c==DIV||(c==MOD&&(p->typf&UNSIGNED)))&&(p->q2.flags&KONST)){
+ long ln;
+ eval_const(&p->q2.val,t);
+ if(zlleq(l2zl(0L),vlong)&&zulleq(ul2zul(0UL),vulong)){
+ if(ln=pof2(vulong)){
+ if(c==MOD){
+ vlong=zlsub(vlong,l2zl(1L));
+ p->code=AND;
+ }else{
+ vlong=l2zl(ln-1);
+ if(c==DIV) p->code=RSHIFT; else p->code=LSHIFT;
+ }
+ c=p->code;
+ if((t&NU)==CHAR) p->q2.val.vchar=zl2zc(vlong);
+ if((t&NU)==SHORT) p->q2.val.vshort=zl2zs(vlong);
+ if((t&NU)==INT) p->q2.val.vint=zl2zi(vlong);
+ if((t&NU)==LONG) p->q2.val.vlong=vlong;
+ vulong=zl2zul(vlong);
+ if((t&NU)==(UNSIGNED|CHAR)) p->q2.val.vuchar=zul2zuc(vulong);
+ if((t&NU)==(UNSIGNED|SHORT)) p->q2.val.vushort=zul2zus(vulong);
+ if((t&NU)==(UNSIGNED|INT)) p->q2.val.vuint=zul2zui(vulong);
+ if((t&NU)==(UNSIGNED|LONG)) p->q2.val.vulong=vulong;
+ }
+ }
+ }
+ if(c==MOD||c==DIV){
+ int m=0;
+ if(regs[ax]&&(!isreg(z)||p->z.reg!=ax)){
+ fprintf(f,"\tpushl\t%s\n",regnames[ax]);
+ stackoffset-=4;m|=1;
+ }
+ if(regs[dx]&&(!isreg(z)||p->z.reg!=dx)){
+ fprintf(f,"\tpushl\t%s\n",regnames[dx]);
+ stackoffset-=4;m|=2;
+ }
+ if((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&(p->q2.reg==ax||p->q2.reg==dx)){
+ move(f,&p->q2,0,0,dx,t);
+ fprintf(f,"\tpushl\t%s\n",regnames[dx]);
+ m|=8;stackoffset-=4;
+ }
+ move(f,&p->q1,0,0,ax,t);
+ if(p->q2.flags&KONST){
+ fprintf(f,"\tpush%c\t",x_t[t&NQ]);probj2(f,&p->q2,t);
+ fprintf(f,"\n");m|=4;stackoffset-=4;
+ }
+ if(t&UNSIGNED) fprintf(f,"\txorl\t%s,%s\n\tdivl\t",regnames[dx],regnames[dx]);
+ else fprintf(f,"\tcltd\n\tidivl\t");
+ if((m&12)||(isreg(q2)&&p->q2.reg==dx)){
+ fprintf(f,"(%s)",regnames[sp]);
+ }else if(isreg(q2)&&p->q2.reg==ax){
+ fprintf(f,"%s(%s)",(m&2)?"4":"",regnames[sp]);
+ }else{
+ probj2(f,&p->q2,t);
+ }
+ fprintf(f,"\n");
+ if(c==DIV) move(f,0,ax,&p->z,0,t);
+ else move(f,0,dx,&p->z,0,t);
+ if(m&4){ fprintf(f,"\taddl\t$%ld,%s\n",zl2l(sizetab[t&NQ]),regnames[sp]);stackoffset+=4;}
+ if(m&8){ fprintf(f,"\tpopl\t%s\n",regnames[dx]);stackoffset+=4;}
+ if(m&2){ fprintf(f,"\tpopl\t%s\n",regnames[dx]);stackoffset+=4;}
+ if(m&1){ fprintf(f,"\tpopl\t%s\n",regnames[ax]);stackoffset+=4;}
+ continue;
+ }
+ if(!(p->q2.flags&KONST)&&(c==LSHIFT||c==RSHIFT)){
+ char *s=arithmetics[c-LSHIFT];
+ int fl=0;
+ if(c==RSHIFT&&(t&UNSIGNED)) s="shr";
+ if(((p->q1.flags®)&&p->q1.reg==cx)||((p->z.flags®)&&p->z.reg==cx)
+ ||(!compare_objects(&p->q1,&p->z)&&!isreg(q1))){
+ reg=get_reg(f,p);
+ move(f,&p->q1,0,0,reg,t);
+ move(f,&p->q2,0,0,cx,t);
+ fprintf(f,"\t%s%c\t%%cl,%s\n",s,x_t[t&NQ],regnames[reg]);
+ move(f,0,reg,&p->z,0,t);
+ continue;
+ }else{
+ if(!isreg(q2)||p->q2.reg!=cx){
+ if(regs[cx]){fprintf(f,"\tpushl\t%s\n",regnames[cx]);fl=1;}
+ move(f,&p->q2,0,0,cx,t);
+ }
+ if(compare_objects(&p->q1,&p->z)){
+ fprintf(f,"\t%s%c\t%%cl,",s,x_t[t&NQ]);
+ probj2(f,&p->z,t);fprintf(f,"\n");
+ }else{
+ move(f,0,p->q1.reg,&p->z,0,t);
+ fprintf(f,"\t%s%c\t%%cl,",s,x_t[t&NQ]);
+ probj2(f,&p->z,t);fprintf(f,"\n");
+ }
+ if(fl) fprintf(f,"\tpopl\t%s\n",regnames[cx]);
+ continue;
+ }
+ }
+ if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)){
+ char *s;
+ if(c>=OR&&c<=AND) s=logicals[c-OR];
+ else s=arithmetics[c-LSHIFT];
+ if(c==RSHIFT&&(t&UNSIGNED)) s="shr";
+ if(c!=MULT&&compare_objects(&p->q1,&p->z)){
+ if(isreg(z)||isreg(q1)||(p->q2.flags&KONST)){
+ if((p->q2.flags&KONST)&&(c==ADD||c==SUB)){
+ eval_const(&p->q2.val,t);
+ if(zleqto(vlong,l2zl(1L))&&zuleqto(vulong,ul2zul(1UL))&&zdeqto(vdouble,d2zd(1.0))){
+ if(c==ADD) s="inc"; else s="dec";
+ fprintf(f,"\t%s%c\t",s,x_t[t&NQ]);
+ probj2(f,&p->z,t);fprintf(f,"\n");
+ continue;
+ }
+ }
+ fprintf(f,"\t%s%c\t",s,x_t[t&NQ]);
+ probj2(f,&p->q2,t);fprintf(f,",");
+ probj2(f,&p->z,t);fprintf(f,"\n");
+ continue;
+ }else{
+ if(isreg(q2)) reg=p->q2.reg; else reg=get_reg(f,p);
+ move(f,&p->q2,0,0,reg,t);
+ fprintf(f,"\t%s%c\t%s",s,x_t[t&NQ],regnames[reg]);
+ fprintf(f,","); probj2(f,&p->z,t);fprintf(f,"\n");
+ continue;
+ }
+ }
+ if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p);
+ move(f,&p->q1,0,0,reg,t);
+ if((p->q2.flags&KONST)&&(c==ADD||c==SUB)){
+ eval_const(&p->q2.val,t);
+ if(zleqto(vlong,l2zl(1L))&&zuleqto(vulong,ul2zul(1UL))&&zdeqto(vdouble,d2zd(1.0))){
+ if(c==ADD) s="inc"; else s="dec";
+ fprintf(f,"\t%s%c\t%s\n",s,x_t[t&NQ],regnames[reg]);
+ }else{
+ fprintf(f,"\t%s%c\t",s,x_t[t&NQ]);
+ probj2(f,&p->q2,t);fprintf(f,",%s\n",regnames[reg]);
+ }
+ }else{
+ fprintf(f,"\t%s%c\t",s,x_t[t&NQ]);
+ probj2(f,&p->q2,t);fprintf(f,",%s\n",regnames[reg]);
+ }
+ move(f,0,reg,&p->z,0,t);
+ continue;
+ }
+ ierror(0);
+ }
+ if(notpopped){
+ fprintf(f,"\taddl\t$%ld,%%esp\n",notpopped);
+ stackoffset+=notpopped;notpopped=0;
+ }
+ function_bottom(f,v,loff);
+}
+
+int shortcut(int code,int typ)
+{
+ return(0);
+}
+
+void cleanup_cg(FILE *f)
+{
+ struct fpconstlist *p;
+ unsigned char *ip;
+
+ title(f);
+ while(p=firstfpc){
+ if(f){
+ if(section!=CODE){fprintf(f,codename);section=CODE;}
+ fprintf(f,"%s%d:\n\t.long\t",labprefix,p->label);
+ ip=(unsigned char *)&p->val.vdouble;
+ fprintf(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+ if((p->typ&NQ)==DOUBLE){
+ fprintf(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+ }
+ fprintf(f,"\n");
+ }
+ firstfpc=p->next;
+ free(p);
+ }
+ if(f){
+ if(section!=BSS){fprintf(f,bssname);section=BSS;}
+ if(cxl) fprintf(f,"\t.lcomm\t%s%d,4\n",labprefix,cxl);
+ if(sil) fprintf(f,"\t.lcomm\t%s%d,4\n",labprefix,sil);
+ if(dil) fprintf(f,"\t.lcomm\t%s%d,4\n",labprefix,dil);
+ }
+}
diff --git a/machines/bi386/machine.dt b/machines/bi386/machine.dt
new file mode 100755
index 0000000..94451a4
--- /dev/null
+++ b/machines/bi386/machine.dt
@@ -0,0 +1,13 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/bi386/machine.h b/machines/bi386/machine.h
new file mode 100755
index 0000000..5970ac1
--- /dev/null
+++ b/machines/bi386/machine.h
@@ -0,0 +1,59 @@
+/* Example of a code-generator for an Intel 386 or higher. */
+
+#include "dt.h"
+
+#define BEI386
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Not used in this code-generrator. */
+struct AddressingMode{
+ int never_used;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR 16
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 10
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 0
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P INT
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#ifdef BEI386
+#define BIGENDIAN 1
+#else
+#define BIGENDIAN 0
+#endif
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#ifdef BEI386
+#define LITTLEENDIAN 0
+#else
+#define LITTLEENDIAN 1
+#endif
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+
diff --git a/machines/c16x/machine.c b/machines/c16x/machine.c
new file mode 100755
index 0000000..b80fd10
--- /dev/null
+++ b/machines/c16x/machine.c
@@ -0,0 +1,3728 @@
+/* Code generator for SAB c16x microcontrollers. */
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for c16x V0.3 (c) in 1998-2005 by Volker Barthelmann";
+
+/* Commandline-flags the code-generator accepts */
+int g_flags[MAXGF]={VALFLAG,0,0,0,
+ 0,0,0,0,
+ 0};
+char *g_flags_name[MAXGF]={"cpu","int32","no-delayed-popping","const-in-data",
+ "merge-constants","no-peephole","mtiny","mlarge",
+ "mhuge","tasking"};
+union ppi g_flags_val[MAXGF];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","bit","char","short","int","long","long long",
+ "float","double","long double","void",
+ "near-pointer","far-pointer","huge-pointer",
+ "array","struct","union","enum","function"};
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT of the target machine. */
+zmax char_bit;
+
+/* Sizes of all elementary types in bytes. */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. */
+char *regnames[]={"noreg","R0","R1","R2","R3","R4","R5","R6","R7",
+ "R8","R9","R10","R11","R12","R13","R14","R15",
+ "R6/R7","R7/R8","R8/R9","R4/R5",
+ "R14/R15","R13/R14","R12/R13",
+ "R3/R4","R2/R3",
+ "MAXR+1","MAXR+2","ZEROS","ONES"};
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* Type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1]={0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1};
+
+int reg_prio[MAXR+1]={0,0,0,0,0,2,3,1,1,1,1,0,0,4,5,6,7,1,1,1,2,6,5,4,0,0};
+
+struct reg_handle empty_reg_handle={0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__interrupt","__dpp0","__dpp1","__dpp2","__dpp3",0};
+#define INTERRUPT 1
+#define DPP0 2
+#define DPP1 4
+#define DPP2 8
+#define DPP3 16
+
+
+/****************************************/
+/* Some private data and functions. */
+/****************************************/
+
+static char *bregnames[]={"nobreg","RL0","RL1","RL2","RL3","RL4","RL5","RL6","RL7",
+ "e8","e9","e10","e11","e12","e13","e14","e15","e16",
+ "e17","e18","e19","e20","e21","e22"
+};
+
+static long malign[MAX_TYPE+1]= {1,1,1,2,2,2,2,2,2,2,1,2,2,2,1,1,1,2,1};
+static long msizetab[MAX_TYPE+1]={0,1,1,2,2,4,8,4,8,8,0,2,4,4,0,0,0,2,0};
+
+struct Typ ityp={SHORT},ltyp={LONG};
+
+#define INT32 (g_flags[1]&USEDFLAG)
+#define TINY (g_flags[6]&USEDFLAG)
+#define LARGE (g_flags[7]&USEDFLAG)
+#define HUGE (g_flags[8]&USEDFLAG)
+#define TASKING (g_flags[9]&USEDFLAG)
+
+
+#define NDATA 0
+#define NBSS 1
+#define NCDATA 2
+#define FDATA 3
+#define FBSS 4
+#define FCDATA 5
+#define HDATA 6
+#define HBSS 7
+#define HCDATA 8
+#define CODE 9
+#define SPECIAL 10
+#define BITS 11
+
+#define SEG r2
+#define SOF r1
+
+#define MTMP1 MAXR+1
+#define MTMP2 MAXR+2
+#define ZEROS MAXR+3
+#define ONES MAXR+4
+
+static int section=-1,newobj,scnt;
+static char *codename="SCODE\tSECTION CODE WORD PUBLIC 'CPROGRAM'\n",*ecode="SCODE\tends\n",
+ *ndataname="NDATA\tSECTION LDAT WORD PUBLIC\n",*endata="NDATA\tends\n",
+ *fdataname="FDATA\tSECTION LDAT WORD PUBLIC\n",*efdata="FDATA\tends\n",
+ *hdataname="HDATA\tSECTION LDAT WORD PUBLIC\n",*ehdata="HDATA\tends\n",
+ *nbssname="NBSS\tSECTION LDAT WORD PUBLIC\n",*enbss="NBSS\tends\n",
+ *fbssname="FBSS\tSECTION LDAT WORD PUBLIC\n",*efbss="FBSS\tends\n",
+ *hbssname="HBSS\tSECTION LDAT WORD PUBLIC\n",*ehbss="HBSS\tends\n",
+ *ncdataname="NCDATA\tSECTION LDAT WORD PUBLIC\n",*encdata="NCDATA\tends\n",
+ *fcdataname="FCDATA\tSECTION LDAT WORD PUBLIC\n",*efcdata="FCDATA\tends\n",
+ *hcdataname="HCDATA\tSECTION LDAT WORD PUBLIC\n",*ehcdata="HCDATA\tends\n",
+
+ *bitsname="BITS\tSECTION BIT BIT PUBLIC 'CBITS'\n",*ebits="BITS\tends\n";
+
+static char *even="\teven\n",*public="public",*comment="; ";
+
+#define IMM_IND 1
+#define VAR_IND 2
+#define POST_INC 3
+#define PRE_DEC 4
+
+static char sec_end[32];
+/* (user)stack-pointer, pointer-tmp, int-tmp; reserved for compiler */
+static const int sp=1,tp=2,ti=11,ti2=12,r4=5,r5=6,r4r5=20;
+static int tmp1,tmp2,tmp3,tmp4;
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+static int scratchreg(int,struct IC *);
+static struct Var nvar,fvar;
+
+static char *marray[]={0,
+ "__far=__attr(\"far\")",
+ "__near=__attr(\"near\")",
+ "__huge=__attr(\"huge\")",
+ "__bit=__attr(\"bit\") unsigned char",
+ /*"__section(x)=__vattr(\"section(\"x\")\")",*/
+ "__section(x,y)=__vattr(\"section(\"#x\",\"#y\")\")",
+ "__rbank(x)=__vattr(\"rbank(\"__str(x)\")\")",
+ "__interrupt(x)=__interrupt __vattr(\"ivec(\"__str(x)\")\")",
+ "__sysstack(x)=__stack2(x)",
+ "__usrstack(x)=__stack(x)",
+ "__C16X__",
+ "__C167__",
+ "__ST10__",
+ "__sfr(x)=__vattr(\"sfr(\"__str(x)\")\") extern",
+ "__sfrbit(x,y)=__vattr(\"sfrbit(\"__str(x)\",\"__str(y)\")\") extern",
+ "__esfr(x)=__vattr(\"sfre(\"__str(x)\")\") extern",
+ "__esfrbit(x,y)=__vattr(\"sfrbite(\"__str(x)\",\"__str(y)\")\") extern",
+ "__SIZE_T_INT=1",
+ "__str(x)=#x",
+ 0};
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+#define issfrv(v) (v->vattr&&strstr(v->vattr,"sfr("))
+#define issfrbitv(v) (v->vattr&&strstr(v->vattr,"sfrbit("))
+#define isesfrv(v) (v->vattr&&strstr(v->vattr,"sfre("))
+#define isesfrbitv(v) (v->vattr&&strstr(v->vattr,"sfrbite("))
+#define issfr(x) ((p->x.flags&(VAR|DREFOBJ))==VAR&&issfrv(p->x.v))
+#define issfrbit(x) ((p->x.flags&(VAR|DREFOBJ))==VAR&&issfrbitv(p->x.v))
+#define isesfr(x) ((p->x.flags&(VAR|DREFOBJ))==VAR&&isesfrv(p->x.v))
+#define isesfrbit(x) ((p->x.flags&(VAR|DREFOBJ))==VAR&&isesfrbitv(p->x.v))
+
+static long loff,sysstackoffset,usrstackoffset,notpopped,dontpop,
+ usrmaxpushed,sysmaxpushed,sysstack,usrstack;
+
+static char *x_t[]={"?","","b","","","","","","","","","","","","","",""};
+static char *ccs[]={"z","nz","lt","ge","le","gt"};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"shl","shr","add","sub","mul","div","mod"};
+static char *dct[]={"","dbit","db","dw","dw","dw","dw","dw","dw","dw",
+ "(void)","dw","dsptr","dsptr"};
+static char *vdct[]={"",".bit",".byte",".short",".short",".short",".short",".short",".short",".short",
+ "(void)",".short",".long",".long"};
+static int pushedsize,pushorder=2;
+static char *idprefix="_",*labprefix="l";
+static int ti2_used;
+static struct rpair qp;
+static int exit_label,have_frame,stackchecklabel,stack_valid;
+static char *ret,*call,*jump;
+static int frame_used;
+
+static char *dppprefix="___DPP_";
+static int romdpp=0,ramdpp=1;
+
+#define STR_NEAR "near"
+#define STR_FAR "far"
+#define STR_HUGE "huge"
+#define STR_BADDR "baddr"
+
+#define ISNULL() (zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
+#define ISLWORD(t) ((t&NQ)==LONG||(t&NQ)==FPOINTER||(t&NQ)==HPOINTER||(t&NQ)==FLOAT)
+#define ISHWORD(t) ((t&NQ)==INT||(t&NQ)==SHORT||(t&NQ)==NPOINTER)
+#define ISSTATIC(v) ((v)->storage_class==EXTERN||(v)->storage_class==STATIC)
+#define ISBADDR(v) ((v)->vtyp->attr&&strstr(STR_BADDR,(v)->vtyp->attr))
+
+static int dppuse(struct Var *v,int section)
+{
+ if(v->tattr&DPP0) return 0;
+ if(v->tattr&DPP1) return 1;
+ if(v->tattr&DPP2) return 2;
+ if(v->tattr&DPP3) return 3;
+ if(section==NCDATA) return romdpp;
+ if(section==NDATA||section==NBSS) return ramdpp;
+ return -1;
+}
+
+static int ISFAR(struct Var *v)
+{
+ struct Typ *vt;
+ if(v==&nvar) return 0;
+ if(v==&fvar) return 1;
+ if(issfrv(v)||isesfrv(v)||issfrbitv(v)||isesfrbitv(v))
+ return 0;
+ vt=v->vtyp;
+ while(ISARRAY(vt->flags)) vt=vt->next;
+ if(vt->attr&&strstr(STR_NEAR,vt->attr))
+ return 0;
+ if(HUGE||LARGE)
+ return 1;
+ if(vt->attr&&(strstr(STR_FAR,vt->attr)||strstr(STR_HUGE,vt->attr)))
+ return 1;
+ return 0;
+}
+
+static int special_section(FILE *f,struct Var *v)
+{
+ char *sec,*e;
+ if(!v->vattr) return 0;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return 0;
+ sec+=strlen("section(");
+ if(f&&TASKING){
+ emit(f,sec_end);
+ e=sec_end;
+ while(*sec&&*sec!=')') {
+ *e++=*sec;
+ emit_char(f,*sec++);
+ }
+ *e=0;
+ strcat(sec_end,"\tends\n");
+ emit(f,"\tSECTION LDAT WORD PUBLIC\n");
+ }else{
+ emit(f,"\t.section\t");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ }
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+static struct fpconstlist {
+ struct fpconstlist *next;
+ int label,typ;
+ union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+ struct fpconstlist *p=firstfpc;
+ t&=NQ;
+ if(g_flags[4]&USEDFLAG){
+ for(p=firstfpc;p;p=p->next){
+ if(t==p->typ){
+ eval_const(&p->val,t);
+ if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+ if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+ if(t==LDOUBLE&&zldeqto(vldouble,o->val.vldouble)) return p->label;
+ }
+ }
+ }
+ p=mymalloc(sizeof(struct fpconstlist));
+ p->next=firstfpc;
+ p->label=++label;
+ p->typ=t;
+ p->val=o->val;
+ firstfpc=p;
+ return p->label;
+}
+static void callee_push(long usr,long sys)
+{
+ if(usr-usrstackoffset>usrstack)
+ usrstack=usr-usrstackoffset;
+ if(sys-sysstackoffset>sysstack)
+ sysstack=sys-sysstackoffset;
+}
+static void push(long usr,long sys)
+{
+ usrstackoffset-=usr;
+ if(usrstackoffset<usrmaxpushed)
+ usrmaxpushed=usrstackoffset;
+ if(-usrmaxpushed>usrstack) usrstack=-usrmaxpushed;
+ sysstackoffset-=sys;
+ if(sysstackoffset<sysmaxpushed)
+ sysmaxpushed=sysstackoffset;
+ if(-sysmaxpushed>sysstack) sysstack=-sysmaxpushed;
+}
+static void pop(long usr,long sys)
+{
+ usrstackoffset+=usr;
+ sysstackoffset+=sys;
+}
+int pointer_type(struct Typ *p)
+{
+ struct Typ *merk=p;
+ if(!p) ierror(0);
+ while(ISARRAY(p->flags)||ISFUNC(p->flags)) p=p->next;
+ if(p->attr){
+ if(strstr(p->attr,STR_HUGE)) return HPOINTER;
+ if(strstr(p->attr,STR_FAR)) return FPOINTER;
+ if(strstr(p->attr,STR_NEAR)) return NPOINTER;
+ }
+ if((merk->flags&NQ)==FUNKT){
+ if(TINY)
+ return NPOINTER;
+ else
+ return HPOINTER;
+ }
+ if(LARGE)
+ return FPOINTER;
+ else if(HUGE)
+ return HPOINTER;
+ else
+ return NPOINTER;
+}
+static long voff(struct obj *p)
+{
+ if(p->v->offset<0)
+ return loff-zm2l(p->v->offset)+zm2l(p->val.vmax)-usrstackoffset+pushedsize-2;
+ return zm2l(p->v->offset)+zm2l(p->val.vmax)-usrstackoffset;
+}
+static int alignment(struct obj *o)
+{
+ if(o->flags&DREFOBJ) return 1;
+ if(!(o->flags&VAR)) ierror(0);
+ if(ISSTATIC(o->v)) return zm2l(o->val.vmax)&1;
+ return voff(o)&1;
+}
+
+static int isseg;
+
+static void emit_obj(FILE *f,struct obj *p,int t)
+/* Gibt Objekt auf Bildschirm aus */
+{
+ if(p->am){
+ static struct rpair bp;
+ int base;
+ if(reg_pair(p->am->base,&bp))
+ base=bp.SOF;
+ else
+ base=p->am->base;
+ if(p->am->flags==POST_INC){
+ emit(f,"[%s+]",regnames[base]);
+ return;
+ }else if(p->am->flags==PRE_DEC){
+ emit(f,"[-%s]",regnames[base]);
+ return;
+ }else{
+ emit(f,"[%s+#%ld",regnames[base],p->am->offset);
+ if(p->am->v){
+ if(p->am->v->storage_class==STATIC)
+ emit(f,"+%s%ld",labprefix,zm2l(p->am->v->offset));
+ else
+ emit(f,"+%s%s",idprefix,p->am->v->identifier);
+ }
+ emit(f,"]");
+ return;
+ }
+ }
+ if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,"[");
+ if(p->flags&VARADR) emit(f,"#");
+ if((p->flags&(VAR|REG))==VAR){
+ if(p->v==&nvar||p->v==&fvar){
+ if(p->v==&fvar) emit(f,"SOF ");
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }else if(issfrv(p->v)||isesfrv(p->v)||issfrbitv(p->v)||isesfrbitv(p->v)){
+ emit(f,"%s",p->v->identifier);
+ }else if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+ if(voff(p))
+ emit(f,"[%s+#%ld]",regnames[sp],voff(p));
+ else emit(f,"[%s]",regnames[sp]);
+ }else{
+ if(!isseg&&!ISFUNC(p->v->vtyp->flags)){
+ if(ISFAR(p->v))
+ emit(f,"SOF ");
+ else
+ emit(f,"DPPX:");
+ }
+ isseg=0;
+ if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ }
+ }
+ if(p->flags®){
+ if(p->reg==MTMP1||p->reg==MTMP2){
+ if(!reg_pair(p->reg,&rp)) ierror(0);
+ emit(f,"%s",regnames[rp.SOF]);
+ }else{
+ emit(f,"%s",regnames[p->reg]);
+ if((t&NQ)==BIT) emit(f,".0");
+ }
+ }
+ /* sometimes we just or a REG into a KONST */
+ if((p->flags&(KONST|REG))==KONST){
+ if(ISFLOAT(t)){
+ emit(f,"%s%d",labprefix,addfpconst(p,t));
+ }else{
+ emit(f,"#");emitval(f,&p->val,t&NU);
+ }
+ }
+ if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,"]");
+}
+
+static void pr(FILE *f,struct IC *p)
+{
+}
+static int switched_bank;
+static void function_top(FILE *f,struct Var *v,long offset)
+/* erzeugt Funktionskopf */
+{
+ int i;char *tmp;
+ static int wrote_header;
+ if(f&&!wrote_header){
+ wrote_header=1;
+ if(!TASKING){
+ emit(f,"\t.sfr\tZEROS,0xfe,0x8e\n");
+ emit(f,"\t.sfr\tONES,0xfe,0x8f\n");
+ emit(f,"\t.sfr\tCP,0xfe,0x08\n");
+ emit(f,"\t.sfr\tMDH,0xfe,0x06\n");
+ emit(f,"\t.sfr\tMDL,0xfe,0x07\n");
+ emit(f,"\t.sfr\tPSW,0xfe,0x88\n");
+ }
+ }
+ have_frame=0;stack_valid=1;
+ pushedsize=0;
+ if(v->vattr&&(tmp=strstr(v->vattr,"ivec("))){
+ int vec;char c;int rc;
+ rc=sscanf(tmp+5,"%i%c",&vec,&c);
+ if(rc!=2||c!=')') error(324,"illegal vector number");
+ emit(f,"\t.section\t\".ivec%d\",\"axr\"\n",vec);
+ emit(f,"\t.global\tivec%d\nivec%d:\n",vec,vec);
+ if(v->storage_class==EXTERN)
+ emit(f,"\tjmps\t%s%s\n",idprefix,v->identifier);
+ else
+ emit(f,"\tjmps\t%s%ld\n",labprefix,zm2l(v->offset));
+ section=-1;
+ }
+ if(!special_section(f,v)&§ion!=CODE){
+ if(f&&TASKING){
+ emit(f,sec_end);emit(f,codename);
+ section=CODE;
+ strcpy(sec_end,ecode);
+ }else
+ emit(f,codename);
+ }
+ if(TASKING){
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\tpublic\t%s%s\n",idprefix,v->identifier);
+ if(TINY)
+ emit(f,"%s%s\tproc\tnear\n",idprefix,v->identifier);
+ else
+ emit(f,"%s%s\tproc\tfar\n",idprefix,v->identifier);
+ }else{
+ if(TINY)
+ emit(f,"%s%ld\tproc\tnear\n",labprefix,zm2l(v->offset));
+ else
+ emit(f,"%s%ld\tproc\tfar\n",labprefix,zm2l(v->offset));
+ }
+ }else{
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ emit(f,"\t.align\t1\n%s%s:\n",idprefix,v->identifier);
+ }else{
+ emit(f,"\t.align\t1\n%s%ld:\n",labprefix,zm2l(v->offset));
+ }
+ }
+ if(v->vattr&&(tmp=strstr(v->vattr,"rbank("))){
+ char *p;
+ tmp+=strlen("rbank(");
+ emit(f,"\tmov\t%s",idprefix);
+ for(p=tmp;*p&&*p!=')';p++) emit_char(f,*p);
+ emit(f,",%s\n",regnames[sp]);
+ emit(f,"\tscxt\tCP,#%s",idprefix);
+ for(p=tmp;*p&&*p!=')';p++) emit_char(f,*p);
+ emit(f,"\n");
+ switched_bank=1;
+ }else
+ switched_bank=0;
+ if(v->tattr&INTERRUPT){
+ /*FIXME?*/
+ emit(f,"\tpush\tMDL\n");
+ emit(f,"\tpush\tMDH\n");
+ }
+ if(stack_check){
+ stackchecklabel=++label;
+ BSET(regs_modified,tp);
+ emit(f,"\tmov\t%s,#%s%d\n",regnames[tp],labprefix,stackchecklabel);
+ emit(f,"\t%s\t%s__stack_check\n",call,idprefix);/*FIXME:usrstack*/
+ }
+ for(i=1;i<=16;i++){
+ if(regused[i]&&!regscratch[i]&&!regsa[i]){
+ emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[i]);
+ push(2,0);
+ have_frame=1;pushedsize+=2;
+ }
+ }
+ if(offset){
+ emit(f,"\tsub\t%s,#%ld\n",regnames[sp],offset);
+ have_frame=1;
+ }
+}
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/* erzeugt Funktionsende */
+{
+ int i;
+ if(offset) emit(f,"\tadd\t%s,#%ld\n",regnames[sp],offset);
+ for(i=16;i>0;i--){
+ if(regused[i]&&!regscratch[i]&&!regsa[i]){
+ emit(f,"\tmov\t%s,[%s+]\n",regnames[i],regnames[sp]);
+ pop(2,0);
+ }
+ }
+ if(v->tattr&INTERRUPT){
+ emit(f,"\tpop\tMDH\n");
+ emit(f,"\tpop\tMDL\n");
+ }
+ if(switched_bank)
+ emit(f,"\tpop\tCP\n");
+ if(ret) emit(f,"\t%s\n",ret);
+ if(TASKING){
+ if(v->storage_class==EXTERN){
+ emit(f,"%s%s\tendp\n",idprefix,v->identifier);
+ if(!strcmp("main",v->identifier)) emit(f,"\textern\t__CSTART:far\n");
+ }else
+ emit(f,"%s%ld\tendp\n",labprefix,zm2l(v->offset));
+ }else{
+ if(v->storage_class==EXTERN){
+ emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+ emit(f,"\t.size\t%s%s,$-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
+ }else{
+ emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset));
+ emit(f,"\t.size\t%s%ld,$-%s%ld\n",labprefix,zm2l(v->offset),labprefix,zm2l(v->offset));
+ }
+ }
+ if(stack_check)
+ emit(f,"%s%d\tequ\t%ld\n",labprefix,stackchecklabel,offset+pushedsize-usrmaxpushed);
+ if(stack_valid){
+ long ustack=usrstack+offset+pushedsize,sstack=sysstack;
+ if(!v->fi) v->fi=new_fi();
+ if(v->fi->flags&ALL_STACK){
+ if(v->fi->stack1!=ustack)
+ if(f) error(319,"user-",ustack,v->fi->stack1);
+ if(v->fi->stack2!=sstack)
+ if(f) error(319,"system-",sstack,v->fi->stack2);
+ }else{
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=ustack;
+ v->fi->stack2=sstack;
+ }
+#if 0
+ emit(f,"%s usrstacksize=%ld\n",comment,zm2l(v->fi->stack1));
+ emit(f,"%s sysstacksize=%ld\n",comment,zm2l(v->fi->stack2));
+#endif
+ if(TASKING){
+ }else{
+ emit(f,"\t.equ\t%s__ustack_%s,%ld\n",idprefix,v->identifier,zm2l(v->fi->stack1));
+ emit(f,"\t.equ\t%s__sstack_%s,%ld\n",idprefix,v->identifier,zm2l(v->fi->stack2));
+ }
+ }
+}
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+ if(o1->flags==o2->flags&&o1->am==o2->am){
+ if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+ if(!(o1->flags®)||o1->reg==o2->reg){
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+#define EXT_IC_CMPIA 1
+#define EXT_IC_BTST 2
+#define EXT_IC_CMPIB 3
+static void clear_ext_ic(struct ext_ic *p)
+{
+ p->flags=0;
+ p->r=0;
+ p->offset=0;
+}
+static long pof2(zumax x)
+/* Yields log2(x)+1 oder 0. */
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+static void peephole(struct IC *p)
+{
+ int c,c2,r,t;struct IC *p2;
+ struct AddressingMode *am;
+ frame_used=0;
+ for(;p;p=p->next){
+ c=p->code;
+ if(!frame_used){
+ if((p->q1.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q1.v)) frame_used=1;
+ if((p->q2.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q2.v)) frame_used=1;
+ if((p->z.flags&(REG|VAR))==VAR&&!ISSTATIC(p->z.v)) frame_used=1;
+ }
+ /* letztes Label merken */
+ if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+ if(c==LABEL) exit_label=p->typf;
+ /* and x,#const;bne/beq */
+ if(c==AND&&isconst(q2)&&isreg(z)&&!ISLWORD(ztyp(p))){
+ long bit;
+ eval_const(&p->q2.val,p->typf);
+ if(bit=pof2(vumax)){
+ struct IC *cmp=0;int fr=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==TEST){
+ if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg){
+ cmp=p2;continue;
+ }
+ }
+ if(c2==COMPARE&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,p2->typf);
+ if(ISNULL()){
+ cmp=p2;continue;
+ }
+ break;
+ }
+ if(c2==FREEREG&&p2->q1.reg==p->z.reg) {fr++;continue;}
+ if((c2==BNE||c2==BEQ)&&cmp&&fr==1){
+ p->ext.flags=EXT_IC_BTST;
+ p2->ext.flags=EXT_IC_BTST;
+ p2->ext.offset=bit-1;
+ cmp->code=NOP;
+ cmp->q1.flags=cmp->q2.flags=cmp->z.flags=0;
+ break;
+ }
+ if(((p2->q1.flags®)&&p2->q1.reg==p->z.reg)||((p2->q2.flags®)&&p2->q2.reg==p->z.reg)||((p2->z.flags®)&&p2->z.reg==p->z.reg)) break;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ }
+ }
+ }
+ /* [Rx+] in q1 */
+ if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ r=p->q1.reg; t=q1typ(p);
+ if((!(p->q2.flags®)||p->q2.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if((c2==ADD||(c2==ADDI2P&&(p2->typf2&NQ)!=HPOINTER))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,p2->typf2);
+ if((zmeqto(vmax,l2zm(1L))&&(t&NQ)==CHAR)||(zmeqto(vmax,l2zm(2L))&&ISHWORD(t))){
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ p->q1.am=mymalloc(sizeof(*am));
+ p->q1.am->flags=POST_INC;
+ p->q1.am->base=r;
+ }else break;
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(((p2->q1.flags®)&&p2->q1.reg==r)||((p2->q2.flags®)&&p2->q2.reg==r)||((p2->z.flags®)&&p2->z.reg==r)) break;
+ }
+ }
+ }
+ /* [Rx+] in q2 */
+ if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ r=p->q2.reg; t=q2typ(p);
+ if((!(p->q1.flags®)||p->q1.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if((c2==ADD||(c2==ADDI2P&&(p2->typf2&NQ)!=HPOINTER))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,p2->typf2);
+ if((zmeqto(vmax,l2zm(1L))&&(t&NQ)==CHAR)||(zmeqto(vmax,l2zm(2L))&&ISHWORD(t))){
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ p->q2.am=mymalloc(sizeof(*am));
+ p->q2.am->flags=POST_INC;
+ p->q2.am->base=r;
+ }else break;
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(((p2->q1.flags®)&&p2->q1.reg==r)||((p2->q2.flags®)&&p2->q2.reg==r)||((p2->z.flags®)&&p2->z.reg==r)) break;
+ }
+ }
+ }
+ /* move x->t; add/sub x,#1/-1/2/-2-> x; test/cmp t,#0; freereg t => cmpid12 */
+ if(c==ASSIGN&&isreg(q1)&&isreg(z)&&ISHWORD(p->typf)){
+ p2=p->next;if(p2) c2=p2->code;
+ if(p2&&(c2==ADD||c2==SUB||c2==ADDI2P||c2==SUBIFP)&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->q1.reg&&p2->z.reg==p2->q1.reg&&(p2->q2.flags&(KONST|DREFOBJ))==KONST&&ISHWORD(p2->typf)){
+ long l;
+ eval_const(&p2->q2.val,p2->typf);
+ l=zm2l(vmax);
+ if((l==1||l==2||l==-1||l==-2)&&p2->next){
+ struct IC *p3=p2->next;
+ if((p3->code==TEST||(p3->code==COMPARE&&(p3->q2.flags&(KONST|DREFOBJ))==KONST))&&(p3->q1.flags&(REG|DREFOBJ))==REG&&p3->q1.reg==p->z.reg&&scratchreg(p->z.reg,p3)&&ISHWORD(p3->typf)){
+ if(c2==SUB||c2==SUBIFP) l=-l;
+ p3->q1=p->q1;
+ p->code=c=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ p3->ext.flags=EXT_IC_CMPIB;
+ p3->ext.offset=l;
+ p3->ext.r=p->q1.reg;
+ }
+ }
+ }
+ }
+ /* add/sub x,#1/2/-1/-2 ->x; cmp x,#c => cmpid12 x,#c+-12 */
+ if((c==ADD||c==SUB||c==ADDI2P||c==SUBIFP)&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg&&isconst(q2)&&ISHWORD(p->typf)&&!reg_pair(p->q1.reg,&rp)){
+ eval_const(&p->q2.val,p->typf);
+ if(zmeqto(vmax,l2zm(-1L))||zmeqto(vmax,l2zm(-2L))||zmeqto(vmax,l2zm(1L))||zmeqto(vmax,l2zm(2L))){
+ long l=zm2l(vmax);
+ if(c==SUB||c==SUBIFP) l=-l;
+ r=p->q1.reg;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(c2==TEST||(c2==COMPARE&&(p2->q2.flags&(KONST|DREFOBJ))==KONST))&&ISHWORD(p2->typf)){
+ unsigned long ul;
+ eval_const(&p2->q2.val,q2typ(p2));
+ ul=zum2ul(vumax);
+ if(ul<65534){
+ p2->ext.flags=EXT_IC_CMPIA;
+ p2->ext.offset=l;
+ p2->ext.r=r;
+ p->code=c=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ }
+ break;
+
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if((p2->q1.flags®)&&p2->q1.reg==r) break;
+ if((p2->q2.flags®)&&p2->q2.reg==r) break;
+ if((p2->z.flags®)&&p2->z.reg==r) break;
+ }
+ }
+ }
+ /* [Rx+#const] */
+ if((c==ADDI2P||c==SUBIFP)&&((p->typf2&NQ)==NPOINTER||(p->typf2&NQ)==FPOINTER)&&isreg(z)&&((p->q2.flags&(KONST|DREFOBJ))==KONST||(p->q1.flags&VARADR))){
+ int base;zmax of;struct obj *o;struct Var *v;
+ if(p->q1.flags&VARADR){
+ v=p->q1.v;
+ of=p->q1.val.vmax;
+ r=p->z.reg;
+ if(isreg(q2)) base=p->q2.reg; else base=r;
+ }else{
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ v=0;
+ r=p->z.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ }
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ am->base=base;
+ am->offset=zm2l(of);
+ am->v=v;
+ if(!v){
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }else{
+ if(isreg(q2)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q1=p->q2;p->q2.flags=0;
+ p->q2.val.vmax=sizetab[p->typf&NQ];
+ }
+ }
+ }
+ break;
+ }
+ if(/*get_reg!! c2!=FREEREG&&*/m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+}
+
+static struct obj *cam(int flags,int base,long offset,struct Var *v)
+/* Initializes an addressing-mode structure and returns a pointer to */
+/* that object. Will not survive a second call! */
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ am.offset=offset;
+ am.v=v;
+ return &obj;
+}
+/* prints label types used by tasking assembler */
+static void emit_label_type(FILE *f,struct Var *v)
+{
+ if(TASKING){
+ if(ISFUNC(v->vtyp->flags)){
+ if(TINY)
+ emit(f,"near");
+ else
+ emit(f,"far");
+ }else{
+ if((v->vtyp->flags&NQ)==BIT)
+ emit(f,"bit");
+ else if((v->vtyp->flags&NQ)==CHAR)
+ emit(f,"byte");
+ else
+ emit(f,"word");
+ }
+ }
+}
+static void move(FILE *f,struct obj *q,int qr,struct obj *z,int zr,int t)
+/* Generates code to move object q (or register qr) into object z (or */
+/* register zr). One must be a register and DREFOBJ only allowed with */
+/* registers. */
+{
+ long l=0;
+ t&=NQ;
+ if(q&&(q->flags&(REG|DREFOBJ))==REG) qr=q->reg;
+ if(z&&(z->flags&(REG|DREFOBJ))==REG) zr=z->reg;
+ if(qr&&qr==zr) return;
+ if((t&NQ)==BIT){
+ if(!zr&&((z->flags&(VAR|REG|DREFOBJ|VARADR))!=VAR||!ISSTATIC(z->v))) ierror(0);
+ if(q&&(q->flags&(KONST|DREFOBJ))==KONST){
+ if(z&&(z->flags&(VAR|DREFOBJ))==VAR&&isesfrbitv(z->v))
+ emit(f,"\textr\t#1\n");
+ eval_const(&q->val,BIT);
+ if(zmeqto(vmax,l2zm(0L)))
+ emit(f,"\tbclr\t");
+ else
+ emit(f,"\tbset\t");
+ if(zr) emit(f,"%s.0",regnames[zr]); else emit_obj(f,z,t);
+ emit(f,"\n");
+ }else{
+ if(!qr&&((q->flags&(VAR|REG|DREFOBJ|VARADR))!=VAR||!ISSTATIC(q->v))) ierror(0);
+ if((q->flags&(VAR|DREFOBJ))==VAR&&isesfrbitv(q->v)){
+ if(!zr&&((z->flags&(VAR|DREFOBJ))!=VAR||!isesfrbitv(z->v))){
+ emit(f,"\textr\t#1\n");
+ emit(f,"\tbmov\t%s.0,",regnames[ti]);
+ if(qr) emit(f,"%s.0",regnames[qr]); else emit_obj(f,q,t);
+ emit(f,"\n");
+ emit(f,"\tbmov\t");
+ if(zr) emit(f,"%s.0",regnames[zr]); else emit_obj(f,z,t);
+ emit(f,",%s.0\n",regnames[ti]);
+ return;
+ }else
+ emit(f,"\textr\t#1\n");
+ }else if(z&&(z->flags&(VAR|DREFOBJ))==VAR&&isesfrbitv(z->v)){
+ if(!qr){
+ emit(f,"\tbmov\t%s.0,",regnames[ti]);
+ if(qr) emit(f,"%s.0",regnames[qr]); else emit_obj(f,q,t);
+ emit(f,"\n");
+ emit(f,"\textr\t#1\n");
+ emit(f,"\tbmov\t");emit_obj(f,z,t);
+ emit(f,",%s.0\n",regnames[ti]);
+ return;
+ }else
+ emit(f,"\textr\t#1\n");
+ }
+ emit(f,"\tbmov\t");
+ if(zr) emit(f,"%s.0",regnames[zr]); else emit_obj(f,z,t);
+ emit(f,",");
+ if(qr) emit(f,"%s.0",regnames[qr]); else emit_obj(f,q,t);
+ emit(f,"\n");
+ }
+ return;
+ }
+ if(q){
+ if(!zr) ierror(0);
+ if(q->am&®_pair(q->am->base,&rp)){
+ l=rp.SOF;
+ if(zr>16)
+ emit(f,"\texts\t%s,#2\n",regnames[rp.SEG]);
+ else
+ emit(f,"\texts\t%s,#1\n",regnames[rp.SEG]);
+ }else if((q->flags&DREFOBJ)&®_pair(q->reg,&rp)){
+ l=rp.SOF;
+ if(zr>16)
+ emit(f,"\texts\t%s,#2\n",regnames[rp.SEG]);
+ else
+ emit(f,"\texts\t%s,#1\n",regnames[rp.SEG]);
+ }else if((q->flags&(VAR|REG|VARADR))==VAR&&ISSTATIC(q->v)&&ISFAR(q->v)){
+ emit(f,"\texts\t#SEG ");
+ isseg=1;emit_obj(f,q,INT);
+ if(zr>16)
+ emit(f,",#2\n");
+ else
+ emit(f,",#1\n");
+ }
+ if(reg_pair(zr,&rp)){
+ if(q->am){
+ emit(f,"\tmov\t%s,",regnames[rp.r1]);
+ emit_obj(f,q,t);emit(f,"\n");
+ q->am->offset+=2;
+ emit(f,"\tmov\t%s,",regnames[rp.r2]);
+ emit_obj(f,q,t);emit(f,"\n");
+ q->am->offset-=2;
+ return;
+ }else if(q->flags&DREFOBJ){
+ int tmp=0;
+ if(!(q->flags®)) ierror(0);
+ if(!l) l=q->reg;
+ if(l==rp.r1){
+ tmp=rp.r1;
+ /*FIXME: tp hier immer frei? */
+ BSET(regs_modified,tp);
+ rp.r1=tp;
+ }
+ /*FIXME: test auf scratchreg*/
+ if(q->reg>MAXR){
+ emit(f,"\tmov\t%s,[%s+]\n",regnames[rp.r1],regnames[l]);
+ emit(f,"\tmov\t%s,[%s]\n",regnames[rp.r2],regnames[l]);
+ }else{
+ emit(f,"\tmov\t%s,[%s]\n",regnames[rp.r1],regnames[l]);
+ emit(f,"\tmov\t%s,[%s+#2]\n",regnames[rp.r2],regnames[l]);
+ }
+ if(tmp) emit(f,"\tmov\t%s,%s\n",regnames[tmp],regnames[rp.r1]);
+ return;
+ }else if(q->flags&VARADR){
+ q->flags&=~VARADR;
+ emit(f,"\tmov\t%s,#",regnames[rp.r1]);emit_obj(f,q,t);emit(f,"\n");
+ emit(f,"\tmov\t%s,#SEG ",regnames[rp.r2]);isseg=1;emit_obj(f,q,t);emit(f,"\n");
+ q->flags|=VARADR;
+ return;
+ }else if((q->flags&(KONST|DREFOBJ))==KONST){
+ long l2;
+ if(ISFLOAT(t)) ierror(0);
+ eval_const(&q->val,t);
+ l=zm2zl(zmand(vmax,l2zm(65535L)));
+ emit(f,"\tmov\t%s,#%ld\n",regnames[rp.r1],l);
+ l2=zm2l(zmrshift(vmax,l2zm(16L)));
+ if(l2==l) emit(f,"\tmov\t%s,%s\n",regnames[rp.r2],regnames[rp.r1]);
+ else emit(f,"\tmov\t%s,#%ld\n",regnames[rp.r2],l2);
+ return;
+ }else if(qr){
+ if(!reg_pair(qr,&qp)) ierror(0);
+ emit(f,"\tmov\t%s,%s\n",regnames[rp.r1],regnames[qp.r1]);
+ emit(f,"\tmov\t%s,%s\n",regnames[rp.r2],regnames[qp.r2]);
+ return;
+ }else{
+ if(!(q->flags&VAR)) ierror(0);
+ if(q->v->storage_class==AUTO||q->v->storage_class==REGISTER){
+ l=voff(q);
+ if(l)
+ emit(f,"\tmov\t%s,[%s+#%ld]\n",regnames[rp.r1],regnames[sp],l);
+ else
+ emit(f,"\tmov\t%s,[%s]\n",regnames[rp.r1],regnames[sp]);
+ emit(f,"\tmov\t%s,[%s+#%ld]\n",regnames[rp.r2],regnames[sp],l+2);
+ return;
+ }else{
+ emit(f,"\tmov\t%s,",regnames[rp.r1]);emit_obj(f,q,t);emit(f,"\n");
+ emit(f,"\tmov\t%s,",regnames[rp.r2]);emit_obj(f,q,t);emit(f,"+2\n");
+ return;
+ }
+ }
+ ierror(0);
+ }else{
+ emit(f,"\tmov%s\t%s,",x_t[t&NQ],(t==CHAR?bregnames[zr]:regnames[zr]));
+ if(qr&&t==CHAR)
+ emit(f,"%s",bregnames[qr]);
+ else if(!q->am&&(q->flags&(REG|DREFOBJ))==(REG|DREFOBJ)&®_pair(q->reg,&rp))
+ emit(f,"[%s]",regnames[rp.SOF]);
+ else
+ emit_obj(f,q,t);
+ emit(f,"\n");
+ return;
+ }
+ }
+ if(z){
+ if(!qr) ierror(0);
+ if(z->am&®_pair(z->am->base,&rp)){
+ l=rp.SOF;
+ if(qr>16)
+ emit(f,"\texts\t%s,#2\n",regnames[rp.SEG]);
+ else
+ emit(f,"\texts\t%s,#1\n",regnames[rp.SEG]);
+ }else if((z->flags&DREFOBJ)&®_pair(z->reg,&rp)){
+ l=rp.SOF;
+ if(qr>16)
+ emit(f,"\texts\t%s,#2\n",regnames[rp.SEG]);
+ else
+ emit(f,"\texts\t%s,#1\n",regnames[rp.SEG]);
+ }else if((z->flags&(VAR|REG|VARADR))==VAR&&ISSTATIC(z->v)&&ISFAR(z->v)){
+ emit(f,"\texts\t#SEG ");
+ isseg=1;emit_obj(f,z,INT);
+ if(qr>16)
+ emit(f,",#2\n");
+ else
+ emit(f,",#1\n");
+ }
+ if(reg_pair(qr,&rp)){
+ if(z->am){
+ emit(f,"\tmov\t");emit_obj(f,z,t);emit(f,",%s\n",regnames[rp.r1]);
+ z->am->offset+=2;
+ emit(f,"\tmov\t");emit_obj(f,z,t);emit(f,",%s\n",regnames[rp.r2]);
+ z->am->offset-=2;
+ return;
+ }else if(z->flags&DREFOBJ){
+ if(!(z->flags®)) ierror(0);
+ if(!l) l=z->reg;
+ /*FIXME: test auf scratchreg statt >MAXR*/
+ if(z->reg>MAXR&&l!=rp.r2){
+ emit(f,"\tmov\t[%s+],%s\n",regnames[l],regnames[rp.r1]);
+ emit(f,"\tmov\t[%s],%s\n",regnames[l],regnames[rp.r2]);
+ }else{
+ emit(f,"\tmov\t[%s],%s\n",regnames[l],regnames[rp.r1]);
+ emit(f,"\tmov\t[%s+#2],%s\n",regnames[l],regnames[rp.r2]);
+ }
+ return;
+ }else if(zr){
+ if(!reg_pair(zr,&qp)) ierror(0);
+ emit(f,"\tmov\t%s,%s\n",regnames[qp.r1],regnames[rp.r1]);
+ emit(f,"\tmov\t%s,%s\n",regnames[qp.r2],regnames[rp.r2]);
+ return;
+ }else{
+ if(!(z->flags&VAR)) ierror(0);
+ if(z->v->storage_class==AUTO||z->v->storage_class==REGISTER){
+ l=voff(z);
+ if(l)
+ emit(f,"\tmov\t[%s+#%ld],%s\n",regnames[sp],l,regnames[rp.r1]);
+ else
+ emit(f,"\tmov\t[%s],%s\n",regnames[sp],regnames[rp.r1]);
+ emit(f,"\tmov\t[%s+#%ld],%s\n",regnames[sp],l+2,regnames[rp.r2]);
+ return;
+ }else{
+ emit(f,"\tmov\t");emit_obj(f,z,t);emit(f,",%s\n",regnames[rp.r1]);
+ emit(f,"\tmov\t");emit_obj(f,z,t);emit(f,"+2,%s\n",regnames[rp.r2]);
+ return;
+ }
+ }
+ ierror(0);
+ }else{
+ emit(f,"\tmov%s\t",x_t[t&NQ]);
+ if(!z->am&&(z->flags&(REG|DREFOBJ))==(REG|DREFOBJ)&®_pair(z->reg,&rp))
+ emit(f,"[%s]",regnames[rp.SOF]);
+ else if(zr&&t==CHAR)
+ emit(f,"%s",bregnames[zr]);
+ else
+ emit_obj(f,z,t);
+ emit(f,",%s\n",((t==CHAR)?bregnames[qr]:regnames[qr]));
+ return;
+ }
+ }
+ /*reg->reg*/
+ if(t==CHAR){
+ emit(f,"\tmovb\t%s,%s\n",bregnames[zr],bregnames[qr]);
+ }else if(ISLWORD(t)){
+ if(!reg_pair(qr,&qp)) ierror(0);
+ if(!reg_pair(zr,&rp)) ierror(0);
+ emit(f,"\tmov\t%s,%s\n",regnames[rp.r1],regnames[qp.r1]);
+ emit(f,"\tmov\t%s,%s\n",regnames[rp.r2],regnames[qp.r2]);
+ }else{
+ emit(f,"\tmov\t%s,%s\n",regnames[zr],regnames[qr]);
+ }
+}
+
+static int get_reg(FILE *f,struct IC *p)
+{
+ int i;
+ for(i=1;i<=16;i++){
+ if(!regs[i]&®scratch[i]){
+ BSET(regs_modified,i);
+ return i;
+ }
+ }
+ ierror(0);
+}
+
+static void save_result(FILE *f,int r,struct IC *p,int t)
+/* Saves result in register r to object o. May use tp or ti. */
+{
+ if((p->z.flags&(REG|DREFOBJ))==DREFOBJ){
+ BSET(regs_modified,tp);
+ if(ISLWORD(p->z.dtyp)){
+ if(!ti2_used) tmp4=ti2; else tmp4=get_reg(f,p);
+ BSET(regs_modified,tmp3);
+ tmp3=tp;
+ p->z.flags&=~DREFOBJ;
+ move(f,&p->z,0,0,MTMP2,FPOINTER);
+ p->z.flags=(DREFOBJ|REG);
+ p->z.reg=MTMP2;
+ }else if(!(p->z.flags&KONST)){
+ int tmp=(r==tp)?ti:tp;
+ BSET(regs_modified,tmp);
+ p->z.flags&=~DREFOBJ;
+ move(f,&p->z,0,0,tmp,NPOINTER);
+ p->z.flags=(DREFOBJ|REG);
+ p->z.reg=tmp;
+ }
+ }
+ move(f,0,r,&p->z,0,t);
+}
+
+static int scratchreg(int r,struct IC *p)
+{
+ int c;
+ if(r==tp||r==ti||r==ti2||r==MTMP1||r==MTMP2)
+ return 1;
+ while(1){
+ p=p->next;
+ if(!p||((c=p->code)==FREEREG&&p->q1.reg==r)) return 1;
+ if(c==CALL||(c>=BEQ&&c<=BRA)) return 0;
+ if((p->q1.flags®)&&p->q1.reg==r) return 0;
+ if((p->q2.flags®)&&p->q2.reg==r) return 0;
+ if((p->z.flags®)&&p->z.reg==r) return 0;
+ }
+}
+
+static char *longcmd(char *s)
+{
+ if(!strcmp(s,"add")) return "addc";
+ if(!strcmp(s,"sub")) return "subc";
+ /*FIXME*/
+ return s;
+}
+
+/* perform long arithmetic using library functions */
+/* the functions take arguments in r4/r5 and r10/r11 */
+/* giving the result in r4/r5 */
+/* returns , if the operation was performed, 0 if */
+/* the IC should be handled by inline-code */
+static int lib_larith(FILE *f,struct IC *p)
+{
+ int r4p,r5p,c=p->code,t=ztyp(p);char *s;
+ if(regs[r4]&&(!isreg(z)||p->z.reg==r4r5)){
+ emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[r4]);
+ push(2,0);
+ r4p=1;
+ }else
+ r4p=0;
+ if(regs[r5]&&(!isreg(z)||p->z.reg==r4r5)){
+ emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[r5]);
+ push(2,0);
+ r5p=1;
+ }else
+ r5p=0;
+ if(!p->q1.am&&(p->q1.flags&DREFOBJ)){
+ if(!(p->q1.flags&(REG))){
+ if(ISLWORD(p->q1.dtyp)){
+ tmp3=ti2;tmp4=ti;ti2_used=1;
+ BSET(regs_modified,ti);
+ BSET(regs_modified,ti2);
+ p->q1.flags&=~DREFOBJ;
+ move(f,&p->q1,0,0,MTMP2,FPOINTER);
+ p->q1.reg=MTMP2;
+ p->q1.flags=(REG|DREFOBJ);
+ }else if(!(p->q1.flags&KONST)){
+ BSET(regs_modified,ti);
+ p->q1.flags&=~DREFOBJ;
+ move(f,&p->q1,0,0,ti,NPOINTER);
+ p->q1.reg=ti;
+ p->q1.flags=(REG|DREFOBJ);
+ }
+ }
+ }
+ BSET(regs_modified,r4r5);
+ move(f,&p->q1,0,0,r4r5,q1typ(p));
+ if(!p->q2.am&&(p->q2.flags&DREFOBJ)){
+ if(!(p->q2.flags&(REG))){
+ if(ISLWORD(p->q2.dtyp)){
+ BSET(regs_modified,ti);
+ BSET(regs_modified,ti2);
+ tmp3=ti2;tmp4=ti;ti2_used=1;
+ p->q2.flags&=~DREFOBJ;
+ move(f,&p->q2,0,0,MTMP2,FPOINTER);
+ p->q2.reg=MTMP2;
+ p->q2.flags=(REG|DREFOBJ);
+ }else if(!(p->q2.flags&KONST)){
+ BSET(regs_modified,ti);
+ p->q2.flags&=~DREFOBJ;
+ move(f,&p->q2,0,0,ti,NPOINTER);
+ p->q2.reg=ti;
+ p->q2.flags=(REG|DREFOBJ);
+ }
+ }
+ }
+ /* ti/ti2 must be r10/r11 */
+ tmp3=ti;tmp4=ti2;ti2_used=1;
+ BSET(regs_modified,ti);
+ BSET(regs_modified,ti2);
+ move(f,&p->q2,0,0,MTMP2,q2typ(p));
+ if(c==MULT)
+ s="_mul";
+ else if(c==DIV&&(t&UNSIGNED))
+ s="_udil";
+ else if(c==DIV&&!(t&UNSIGNED))
+ s="_sdil";
+ else if(c==MOD&&(t&UNSIGNED))
+ s="_umol";
+ else if(c==MOD&&!(t&UNSIGNED))
+ s="_smol";
+ else
+ ierror(0);
+ if(TASKING){
+ emit(f,"\textern\t%s%s:%s\n",idprefix,s,TINY?"near":"far");
+ emit(f,"\t%s\t%s%s\n",call,idprefix,s);
+ }
+ save_result(f,r4r5,p,ztyp(p));
+ if(r5p){
+ emit(f,"\tmov\t%s,[%s+]\n",regnames[r5],regnames[sp]);
+ pop(2,0);
+ }
+ if(r4p){
+ emit(f,"\tmov\t%s,[%s+]\n",regnames[r4],regnames[sp]);
+ pop(2,0);
+ }
+ return 1;
+}
+
+/****************************************/
+/* End of private fata and functions. */
+/****************************************/
+
+int emit_peephole(void)
+{
+ int entries,i;long x,y,z;
+ char *asmline[EMIT_BUF_DEPTH];
+ i=emit_l;
+ if(emit_f==0)
+ entries=i-emit_f+1;
+ else
+ entries=EMIT_BUF_DEPTH;
+ asmline[0]=emit_buffer[i];
+ if(entries>=1){
+ if(sscanf(asmline[0],"\tshl\tR%ld,#%ld\n",&x,&y)==2&&(y<0||y>15)){
+ sprintf(asmline[0],"\tmov\tR%ld,#0\n",x);
+ return 1;
+ }
+ if(sscanf(asmline[0],"\tshr\tR%ld,#%ld\n",&x,&y)==2&&(y<0||y>15)){
+ sprintf(asmline[0],"\tmov\tR%ld,#0\n",x);
+ return 1;
+ }
+ }
+ if(entries>=2){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[1]=emit_buffer[i];
+ if(sscanf(asmline[0],"\tadd\tR0,#%ld",&x)==1&&sscanf(asmline[1],"\tadd\tR0,#%ld",&y)==1){
+ sprintf(asmline[1],"\tadd\tR0,#%ld\n",x+y);
+ remove_asm();
+ return 1;
+ }
+ if(sscanf(asmline[1],"\tmov\tR11,#%ld",&x)==1&&sscanf(asmline[0],"\texts\tR11,#%ld",&y)==1){
+ sprintf(asmline[1],"\texts\t#%ld,#%ld\n",x,y);
+ remove_asm();
+ return 1;
+ }
+ }
+ if(entries>=3){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[2]=emit_buffer[i];
+ if(sscanf(asmline[2],"\tmov\tR1,#%ld",&x)==1&&sscanf(asmline[1],"\texts\t#%ld,#1",&y)==1&&sscanf(asmline[0],"\tmov\t[R1],R%ld",&z)==1){
+ strcpy(asmline[2],asmline[1]);
+ sprintf(asmline[1],"\tmov\t%ld,R%ld\n",x,z);
+ remove_asm();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int init_cg(void)
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(2L);
+ char_bit=l2zm(8L);
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+ for(i=1;i<=MAXR;i++){
+ if(i<=16){
+ regsize[i]=l2zm(2L);regtype[i]=&ityp;
+ }else{
+ regsize[i]=l2zm(4L);regtype[i]=<yp;
+ }
+ }
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=t_min[SHORT];
+ t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=t_max[SHORT];
+ t_max[LONG]=ul2zum(2147483647UL);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=tu_max[SHORT];
+ tu_max[LONG]=ul2zum(4294967295UL);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ regsa[sp]=regsa[tp]=regsa[ti]=regsa[ti2]=1;
+ regscratch[sp]=regscratch[tp]=regscratch[ti]=regscratch[ti2]=0;
+ target_macros=marray;
+ if(TINY) marray[0]="__TINY__";
+ else if(LARGE) marray[0]="__LARGE__";
+ else if(HUGE) marray[0]="__HUGE__";
+ else marray[0]="__MEDIUM__";
+
+ if(!TASKING){
+ codename="\t.section\t.text,\"carx1\"\n";
+ ndataname="\t.section\t.ndata,\"darw1\"\n";
+ fdataname="\t.section\t.fdata,\"darw1\"\n";
+ hdataname="\t.section\t.hdata,\"darw1\"\n";
+ nbssname="\t.section\t.nbss,\"uarw1\"\n";
+ fbssname="\t.section\t.fbss,\"uarw1\"\n";
+ hbssname="\t.section\t.hbss,\"uarw1\"\n";
+ ncdataname="\t.section\t.ncdata,\"dar1\"\n";
+ fcdataname="\t.section\t.fcdata,\"dar1\"\n";
+ hcdataname="\t.section\t.hcdata,\"dar1\"\n";
+ bitsname="\t.section\t.bits,\"darw0\"\n";
+ even="\t.align\t1\n";
+ public=".global";
+ comment="; ";
+ }
+
+ nvar.storage_class=STATIC;
+ fvar.storage_class=STATIC;
+
+
+ /* TODO: set argument registers */
+ declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+ declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+ declare_builtin("__divsint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__modsint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__lsrsint64",LLONG,LLONG,0,INT,0,1,0);
+ declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+ declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
+ declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
+ declare_builtin("__sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
+ declare_builtin("__uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
+ declare_builtin("__flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
+ declare_builtin("__flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);
+
+ declare_builtin("__flt32toflt64",DOUBLE,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt64toflt32",FLOAT,DOUBLE,0,0,0,1,0);
+
+
+ declare_builtin("__addflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__subflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__mulflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__divflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__negflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__cmpflt32",INT,FLOAT,0,FLOAT,0,1,0);
+
+ declare_builtin("__addflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__subflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__mulflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__divflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__negflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__cmpflt64",INT,DOUBLE,0,DOUBLE,0,1,0);
+
+ return 1;
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+{
+ int f=t->flags&NQ;
+ if(f==LLONG||f==DOUBLE||f==LDOUBLE)
+ return 0;
+ if(ISSCALAR(f)){
+ if(f==LONG||f==FPOINTER||f==HPOINTER)
+ return 20;
+ else
+ return 5;
+ }
+ return 0;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ t&=NQ;
+ if(r==0) return(0);
+ if(mode>0&&!ISPOINTER(t)) return 0;
+ if(t==NPOINTER&&mode>0){
+ if(r<=4) return 1; else return 0;
+ }
+ if(t<=CHAR&&r>8) return 0;
+ if((t<LONG||t==NPOINTER)&&r<=16) return 1;
+ if(t==LONG||t==FLOAT||t==FPOINTER||t==HPOINTER){
+ if(r>16) return 1;
+ }
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ if(r<=16) return 0;
+ if(p){
+ switch(r){
+ case 17: p->r1=7;p->r2=8;break;
+ case 18: p->r1=8;p->r2=9;break;
+ case 19: p->r1=9;p->r2=10;break;
+ case 20: p->r1=5;p->r2=6;break;
+ case 21: p->r1=15;p->r2=16;break;
+ case 22: p->r1=14;p->r2=15;break;
+ case 23: p->r1=13;p->r2=14;break;
+ case 24: p->r1=4;p->r2=5;break;
+ case 25: p->r1=3;p->r2=4;break;
+
+ /* pseudos */
+ case MTMP1: p->r1=tmp1;p->r2=tmp2;break;
+ case MTMP2: p->r1=tmp3;p->r2=tmp4;break;
+ case ZEROS: return 0;
+ case ONES: return 0;
+ default: ierror(0);
+ }
+ }
+ return 1;
+}
+
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+ int c=p->code;
+ if((o->flags&DREFOBJ)){
+ if(o->flags&VKONST) return 1;
+ if(r<=4&&p->q2.flags&&o!=&p->z)
+ return 6;
+ else
+ return 4;
+ }else if(o->flags&VKONST){
+ struct obj *co=&o->v->cobj;
+ if((p->code==ASSIGN&&(p->z.flags&DREFOBJ))||p->code==PUSH)
+ return 4;
+ if(co->flags&VARADR)
+ return 4;
+ if(o==&p->q1)
+ eval_const(&co->val,q1typ(p));
+ else
+ eval_const(&co->val,q2typ(p));
+ /*FIXME*/
+ return 0;
+ }else if(c==GETRETURN&&p->q1.reg==r){
+ return 4;
+ }else if(c==SETRETURN&&p->z.reg==r){
+ return 4;
+ }else if(c==CONVERT&&((p->typf&NQ)==CHAR||(p->typf2&NQ)==CHAR)&®ok(r,CHAR,0)){
+ return 3;
+ }
+ return 2;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* In this generic 32bit RISC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op=o&NQ,tp=t&NQ;
+ if(op==tp) return 0;
+ if(ISHWORD(op)&&ISHWORD(tp)) return 0;
+ if(ISFLOAT(op)||ISFLOAT(tp)) return 1;
+ if(ISLWORD(op)&&ISLWORD(tp)) return 0;
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+#if 0
+ emit(f,"\tds\t%ld\n",zm2l(size));
+#endif
+ /*FIXME: we currently do not use ds because of initialization */
+ long l=zm2l(size);
+ if(TASKING){
+ if(t&&(t->flags&NQ)==BIT){
+ emit(f,"\tdbit\n");
+ return;
+ }
+ /*FIXME:alignment while(size>=4) {emit(f,"\tddw\t0\n");size-=4;}*/
+ while(size--) emit(f,"\tdb\t0\n");
+ }else{
+ if(newobj&§ion!=SPECIAL)
+ emit(f,"%ld\n",zm2l(size));
+ else
+ emit(f,"\t.space\t%ld\n",zm2l(size));
+ newobj=0;
+ }
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ if(section!=BITS&&!zmleq(align,l2zm(1L)))
+ emit(f,even);
+}
+static void new_section(FILE *f,int nsec)
+{
+ if(!f||section==nsec) return;
+ if(TASKING)
+ emit(f,sec_end);
+ section=nsec;
+ if(nsec==HDATA){
+ emit(f,hdataname);
+ strcpy(sec_end,ehdata);
+ }else if(nsec==FDATA){
+ emit(f,fdataname);
+ strcpy(sec_end,efdata);
+ }else if(nsec==NDATA){
+ emit(f,ndataname);
+ strcpy(sec_end,endata);
+ }else if(nsec==HCDATA){
+ emit(f,hcdataname);
+ strcpy(sec_end,ehcdata);
+ }else if(nsec==FCDATA){
+ emit(f,fcdataname);
+ strcpy(sec_end,efcdata);
+ }else if(nsec==NCDATA){
+ emit(f,ncdataname);
+ strcpy(sec_end,encdata);
+ }else if(nsec==HBSS){
+ emit(f,hbssname);
+ strcpy(sec_end,ehbss);
+ }else if(nsec==FBSS){
+ emit(f,fbssname);
+ strcpy(sec_end,efbss);
+ }else if(nsec==NBSS){
+ emit(f,nbssname);
+ strcpy(sec_end,enbss);
+ }else if(nsec==BITS){
+ emit(f,bitsname);
+ strcpy(sec_end,ebits);
+ }
+}
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;
+ char *attr;struct Typ *tv;
+ tv=v->vtyp;
+ while(tv->flags==ARRAY) tv=tv->next;
+ attr=tv->attr;
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(!TASKING){
+ emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset));
+ emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp)));
+ }
+ if(!special_section(f,v)){
+ if((v->vtyp->flags&NQ)==BIT){
+ new_section(f,BITS);
+ }else{
+ if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))){
+ if(attr&&strstr(attr,STR_HUGE))
+ new_section(f,HDATA);
+ else if(attr&&strstr(attr,STR_FAR))
+ new_section(f,FDATA);
+ else if(attr&&strstr(attr,STR_NEAR))
+ new_section(f,NDATA);
+ else{
+ if(HUGE)
+ new_section(f,HDATA);
+ else if(LARGE)
+ new_section(f,FDATA);
+ else
+ new_section(f,NDATA);
+ }
+ }
+ if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)){
+ if(attr&&strstr(attr,STR_HUGE))
+ new_section(f,HCDATA);
+ else if(attr&&strstr(attr,STR_FAR))
+ new_section(f,FCDATA);
+ else if(attr&&strstr(attr,STR_NEAR))
+ new_section(f,NCDATA);
+ else{
+ if(HUGE)
+ new_section(f,HCDATA);
+ else if(LARGE)
+ new_section(f,FCDATA);
+ else
+ new_section(f,NCDATA);
+ }
+ }
+ if(!v->clist){
+ if(attr&&strstr(attr,STR_HUGE))
+ new_section(f,HBSS);
+ else if(attr&&strstr(attr,STR_FAR))
+ new_section(f,FBSS);
+ else if(attr&&strstr(attr,STR_NEAR))
+ new_section(f,NBSS);
+ else{
+ if(HUGE)
+ new_section(f,HBSS);
+ else if(LARGE)
+ new_section(f,FBSS);
+ else
+ new_section(f,NBSS);
+ }
+ }
+ }
+ }
+ gen_align(f,falign(v->vtyp));
+ if(TASKING){
+ emit(f,"%s%ld\tlabel\t",labprefix,zm2l(v->offset));
+ emit_label_type(f,v);
+ emit(f,"\n");
+ }else{
+ if(dppuse(v,section)>=0)
+ emit(f,"\t.set\t%s%s%ld,%d\n",dppprefix,labprefix,zm2l(v->offset),dppuse(v,section));
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }
+ }
+ if(v->storage_class==EXTERN){
+ if(v->flags&(DEFINED|TENTATIVE)){
+ if(!TASKING){
+ emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
+ emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp)));
+ }
+ emit(f,"\t%s\t%s%s\n",public,idprefix,v->identifier);
+ if(!special_section(f,v)){
+ if((v->vtyp->flags&NQ)==BIT){
+ if(f&§ion!=BITS){
+ if(TASKING)
+ emit(f,sec_end);
+ strcpy(sec_end,ebits);
+ emit(f,bitsname);
+ section=BITS;
+ }
+ }else{
+ if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))){
+ if(attr&&strstr(attr,STR_HUGE))
+ new_section(f,HDATA);
+ else if(attr&&strstr(attr,STR_FAR))
+ new_section(f,FDATA);
+ else if(attr&&strstr(attr,STR_NEAR))
+ new_section(f,NDATA);
+ else{
+ if(HUGE)
+ new_section(f,HDATA);
+ else if(LARGE)
+ new_section(f,FDATA);
+ else
+ new_section(f,NDATA);
+ }
+ }
+ if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)){
+ if(attr&&strstr(attr,STR_HUGE))
+ new_section(f,HCDATA);
+ else if(attr&&strstr(attr,STR_FAR))
+ new_section(f,FCDATA);
+ else if(attr&&strstr(attr,STR_NEAR))
+ new_section(f,NCDATA);
+ else{
+ if(HUGE)
+ new_section(f,HCDATA);
+ else if(LARGE)
+ new_section(f,FCDATA);
+ else
+ new_section(f,NCDATA);
+ }
+ }
+ if(!v->clist){
+ if(attr&&strstr(attr,STR_HUGE))
+ new_section(f,HBSS);
+ else if(attr&&strstr(attr,STR_FAR))
+ new_section(f,FBSS);
+ else if(attr&&strstr(attr,STR_NEAR))
+ new_section(f,NBSS);
+ else{
+ if(HUGE)
+ new_section(f,HBSS);
+ else if(LARGE)
+ new_section(f,FBSS);
+ else
+ new_section(f,NBSS);
+ }
+ }
+ }
+ }
+ gen_align(f,falign(v->vtyp));
+ if(TASKING){
+ emit(f,"%s%s\tlabel\t",idprefix,v->identifier);
+ emit_label_type(f,v);
+ emit(f,"\n");
+ }else{
+ if(dppuse(v,section)>=0){
+ emit(f,"\t.global\t%s%s%s\n",dppprefix,idprefix,v->identifier);
+ emit(f,"\t.set\t%s%s%s,%d\n",dppprefix,idprefix,v->identifier,dppuse(v,section));
+ }
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }
+ }else if(strcmp(v->identifier,"__va_start")&&!issfrv(v)&&!isesfrv(v)&&!issfrbitv(v)&&!isesfrbitv(v)){
+ if(TASKING){
+ emit(f,"\textern\t%s%s:",idprefix,v->identifier);
+ emit_label_type(f,v);
+ emit(f,"\n");
+ }else{
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ }
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ if(ISPOINTER(t)){
+ if(p->tree)
+ emit(f,"\t%s\t",TASKING?dct[t&NQ]:vdct[t&NQ]);
+ if(ISLWORD(t))
+ t=UNSIGNED|LONG;
+ else
+ t=UNSIGNED|SHORT;
+ if(!p->tree)
+ emit(f,"\t%s\t",TASKING?dct[t&NQ]:vdct[t&NQ]);
+ }else{
+ emit(f,"\t%s\t",TASKING?dct[t&NQ]:vdct[t&NQ]);
+ }
+ if(!p->tree){
+ if(ISFLOAT(t)){
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+ if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE){
+ emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+ }
+ }else{
+ if(ISLWORD(t)){
+ long l;
+ eval_const(&p->val,t);
+ l=zm2l(zmand(p->val.vmax,l2zm(65535L)));
+ emit(f,"%ld",l);
+ l=zm2l(zmand(zmrshift(p->val.vmax,l2zm(16L)),l2zm(65535L)));
+ emit(f,",%ld",l);
+ }else if((t&NQ)!=BIT)
+ /*FIXME: initialization of bits impossible */
+ emitval(f,&p->val,(t&NU)|UNSIGNED);
+ }
+ }else{
+ int m=p->tree->o.flags;
+ p->tree->o.flags&=~VARADR;
+ emit_obj(f,&p->tree->o,t&NU);
+ p->tree->o.flags=m;
+ }
+ emit(f,"\n");
+}
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+{
+ int c,t,lastcomp=0,reg,short_add,bit_reverse,need_return=0;
+ struct obj *bit_obj;char *bit_reg;
+ static int idone;
+ struct obj o,*cc=0;int cc_t;
+ struct IC *p2;
+ if(TINY){
+ ret="ret";
+ call="calla\tcc_uc,";
+ jump="jmpa\tcc_uc,";
+ }else{
+ ret="rets";
+ call="calls";
+ jump="jmps\t";
+ }
+ if(v->tattr&INTERRUPT)
+ ret="reti";
+ if(DEBUG&1) printf("gen_code()\n");
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_REGS;
+ if(f&&TASKING&&!idone){
+ emit(f,"$EXTEND\n");
+ emit(f,"$MODEL(SMALL)\n");
+ idone=1;
+ }
+ for(p2=p;p2;p2=p2->next) clear_ext_ic(&p2->ext);
+ if(!(g_flags[5]&USEDFLAG)){
+ peephole(p);
+ if(!frame_used) offset=l2zm(0L);
+ }
+ for(c=1;c<=15;c++) regs[c]=regsa[c];
+ regs[16]=0;
+ for(c=1;c<=MAXR;c++){
+ if(regscratch[c]&&(regsa[c]||regused[c])){
+ BSET(regs_modified,c);
+ }
+ }
+ loff=((zm2l(offset)+1)/2)*2;
+ function_top(f,v,loff);
+ usrstackoffset=sysstackoffset=notpopped=dontpop=usrmaxpushed=sysmaxpushed=0;
+ sysstack=usrstack=0;
+ for(;p;pr(f,p),p=p->next){
+ if((p->q1.flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ p->q1.flags=VAR;
+ p->q1.v=ISLWORD(p->q1.dtyp)?&fvar:&nvar;
+ }
+ if((p->q2.flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ p->q2.flags=VAR;
+ p->q2.v=ISLWORD(p->q2.dtyp)?&fvar:&nvar;
+ }
+ if((p->z.flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ p->z.flags=VAR;
+ p->z.v=ISLWORD(p->z.dtyp)?&fvar:&nvar;
+ }
+ if(!TASKING){
+ int rn,rb;char *rs;
+ if(issfr(q1)){
+ rs=strstr(p->q1.v->vattr,"sfr(");
+ sscanf(rs+4,"%i",&rn);
+ if(rn<=255) rn=0xfe00+2*rn;
+ emit(f,"\t.sfr\t%s,%d\n",p->q1.v->identifier,rn);
+ }
+ if(issfr(q2)){
+ rs=strstr(p->q2.v->vattr,"sfr(");
+ sscanf(rs+4,"%i",&rn);
+ if(rn<=255) rn=0xfe00+2*rn;
+ emit(f,"\t.sfr\t%s,%d\n",p->q2.v->identifier,rn);
+ }
+ if(issfr(z)){
+ rs=strstr(p->z.v->vattr,"sfr(");
+ sscanf(rs+4,"%i",&rn);
+ if(rn<=255) rn=0xfe00+2*rn;
+ emit(f,"\t.sfr\t%s,%d\n",p->z.v->identifier,rn);
+ }
+ if(issfrbit(q1)){
+ rs=strstr(p->q1.v->vattr,"sfrbit(");
+ sscanf(rs+7,"%i,%i",&rn,&rb);
+ if(rn<=255) rn=0xfe00+2*rn;
+ emit(f,"\t.sfr\t%s,%d,%d\n",p->q1.v->identifier,rn,rb);
+ }
+ if(issfrbit(q2)){
+ rs=strstr(p->q2.v->vattr,"sfrbit(");
+ sscanf(rs+7,"%i,%i",&rn,&rb);
+ if(rn<=255) rn=0xfe00+2*rn;
+ emit(f,"\t.sfr\t%s,%d,%d\n",p->q2.v->identifier,rn,rb);
+ }
+ if(issfrbit(z)){
+ rs=strstr(p->z.v->vattr,"sfrbit(");
+ sscanf(rs+7,"%i,%i",&rn,&rb);
+ if(rn<=255) rn=0xfe00+2*rn;
+ emit(f,"\t.sfr\t%s,%d,%d\n",p->z.v->identifier,rn,rb);
+ }
+ if(isesfr(q1)){
+ rs=strstr(p->q1.v->vattr,"sfre(");
+ sscanf(rs+5,"%i",&rn);
+ if(rn<=255) rn=0xf000+2*rn;
+ emit(f,"\t.equ\t%s,%d\n",p->q1.v->identifier,rn);
+ }
+ if(isesfr(q2)){
+ rs=strstr(p->q2.v->vattr,"sfre(");
+ sscanf(rs+5,"%i",&rn);
+ if(rn<=255) rn=0xf000+2*rn;
+ emit(f,"\t.equ\t%s,%d\n",p->q2.v->identifier,rn);
+ }
+ if(isesfr(z)){
+ rs=strstr(p->z.v->vattr,"sfre(");
+ sscanf(rs+5,"%i",&rn);
+ if(rn<=255) rn=0xf000+2*rn;
+ emit(f,"\t.equ\t%s,%d\n",p->z.v->identifier,rn);
+ }
+ if(isesfrbit(q1)){
+ rs=strstr(p->q1.v->vattr,"sfrbite(");
+ sscanf(rs+8,"%i,%i",&rn,&rb);
+ if(rn<=255) rn=0xf000+2*rn;
+ emit(f,"\t.sfr\t%s,%d,%d\n",p->q1.v->identifier,rn,rb);
+ }
+ if(isesfrbit(q2)){
+ rs=strstr(p->q2.v->vattr,"sfrbite(");
+ sscanf(rs+8,"%i,%i",&rn,&rb);
+ if(rn<=255) rn=0xf000+2*rn;
+ emit(f,"\t.sfr\t%s,%d,%d\n",p->q2.v->identifier,rn,rb);
+ }
+ if(isesfrbit(z)){
+ rs=strstr(p->z.v->vattr,"sfrbite(");
+ sscanf(rs+8,"%i,%i",&rn,&rb);
+ if(rn<=255) rn=0xf000+2*rn;
+ emit(f,"\t.sfr\t%s,%d,%d\n",p->z.v->identifier,rn,rb);
+ }
+ }
+
+ c=p->code;t=p->typf;
+ ti2_used=0; short_add=0;
+ if(c==NOP) continue;
+ if(c==ALLOCREG){
+ regs[p->q1.reg]=1;
+ if(reg_pair(p->q1.reg,&rp)) regs[rp.r1]=regs[rp.r2]=1;
+ BSET(regs_modified,p->q1.reg);
+ continue;
+ }
+ if(c==FREEREG){
+ regs[p->q1.reg]=0;
+ if(reg_pair(p->q1.reg,&rp)) regs[rp.r1]=regs[rp.r2]=0;
+ continue;
+ }
+ if(notpopped&&!dontpop){
+ int flag=0;
+ if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+ emit(f,"\tadd\t%s,#%ld\n",regnames[sp],notpopped);
+ pop(notpopped,0);notpopped=0;cc=0;
+ }
+ }
+ if(c==LABEL) {cc=0;emit(f,"%s%d:\n",labprefix,t);continue;}
+ if(c>=BEQ&&c<=BGT&&t==exit_label) need_return=1;
+ if(c==BRA){
+ if(p->typf==exit_label&&!have_frame){
+ emit(f,"\t%s\n",ret);
+ }else{
+ if(t==exit_label) need_return=1;
+ emit(f,"\tjmpr\tcc_uc,%s%d\n",labprefix,t);
+ }
+ cc=0;continue;
+ }
+ if(c==BEQ||c==BNE){
+ if(p->ext.flags==EXT_IC_BTST){
+ if(bit_reg){
+ emit(f,"\tj%sb\t%s.%ld,%s%d\n",(c==BEQ)?"n":"",bit_reg,p->ext.offset,labprefix,t);
+ }else{
+ if(!bit_obj) ierror(0);
+ emit(f,"\tj%sb\t",(c==BEQ)?"n":"");
+ emit_obj(f,bit_obj,t);emit(f,".%ld,%s%d\n",p->ext.offset,labprefix,t);
+ }
+ }else if(lastcomp==BIT){
+ if(c==BEQ) bit_reverse=1-bit_reverse;
+ emit(f,"\tj%sb\t",(bit_reverse==1)?"n":"");
+ if(bit_obj)
+ emit_obj(f,bit_obj,t);
+ else
+ emit(f,"%s",bit_reg);
+ emit(f,",%s%d\n",labprefix,t);
+ }else
+ emit(f,"\tjmpr\tcc_%s,%s%d\n",ccs[c-BEQ],labprefix,t);
+ cc=0;continue;
+ }
+ if(c>BNE&&c<BRA){
+ if(p->ext.flags==EXT_IC_BTST||lastcomp==BIT) ierror(0);
+ if(lastcomp&UNSIGNED) emit(f,"\tjmpr\tcc_u%s,%s%d\n",ccs[c-BEQ],labprefix,t);
+ else emit(f,"\tjmpr\tcc_s%s,%s%d\n",ccs[c-BEQ],labprefix,t);
+ cc=0;continue;
+ }
+ if(c==MOVETOREG){
+ move(f,&p->q1,0,0,p->z.reg,SHORT);
+ cc=&p->q1;cc_t=SHORT;continue;
+ }
+ if(c==MOVEFROMREG){
+ move(f,0,p->q1.reg,&p->z,0,SHORT);
+ cc=&p->z;cc_t=SHORT;continue;
+ }
+
+ if((t&NQ)==DOUBLE) {pric2(stdout,p);ierror(0);}
+ if((t&NQ)==BIT){
+ cc=0;
+ if(c==ASSIGN){
+ if(!isreg(z)&&((p->z.flags&(VAR|REG|DREFOBJ|VARADR))!=VAR||!ISSTATIC(p->z.v))) ierror(0);
+ move(f,&p->q1,0,&p->z,0,t);
+ continue;
+ }
+ if(c==COMPARE){
+ if(!isconst(q2)){
+ if(!isreg(q2)&&((p->q2.flags&(VAR|REG|DREFOBJ|VARADR))!=VAR||!ISSTATIC(p->q2.v))) ierror(0);
+ bit_reg="PSW.1";bit_obj=0;lastcomp=BIT;bit_reverse=1;
+ if(isesfrbit(q1)){
+ if(!isesfrbit(q2)&&!isreg(q2)){
+ move(f,&p->q1,0,0,ti,t);
+ emit(f,"\tbcmp\t%s.0,",regnames[ti]);
+ emit_obj(f,&p->q2,t);emit(f,"\n");
+ continue;
+ }else
+ emit(f,"\textr\t#1\n");
+ }else if(isesfrbit(q2)){
+ if(!isreg(q1)){
+ move(f,&p->q2,0,0,ti,t);
+ emit(f,"\tbcmp\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,",%s.0\n",regnames[ti]);
+ continue;
+ }else
+ emit(f,"\textr\t#1\n");
+ }
+ emit(f,"\tbcmp\t");emit_obj(f,&p->q1,t);
+ emit(f,",");emit_obj(f,&p->q2,t);emit(f,"\n");
+ }else{
+ bit_reg=0;bit_obj=&p->q1;lastcomp=BIT;
+ eval_const(&p->q2.val,t);
+ if(ISNULL())
+ bit_reverse=0;
+ else
+ bit_reverse=1;
+ if(isesfrbit(q1)) emit(f,"\textr\t#1\n");
+ }
+ continue;
+ }
+ if(c==TEST){
+ bit_reg=0;bit_obj=&p->q1;bit_reverse=0;lastcomp=BIT;
+ if(isesfrbit(q1)) emit(f,"\textr\t#1\n");
+ continue;
+ }
+ if(c==AND||c==OR||c==XOR){
+ char *s;
+ if(compare_objects(&p->z,&p->q2)){
+ struct obj m;
+ m=p->q1;p->q1=p->q2;p->q2=m;
+ }
+ if(!compare_objects(&p->q1,&p->z))
+ move(f,&p->q1,0,&p->z,0,t);
+ /*FIXME: const, esfr etc. */
+ if(c==AND) s="band";
+ else if(c==OR) s="bor";
+ else s="bxor";
+ if(isesfrbit(q2)&&!isesfrbit(z)&&!isreg(z)){
+ move(f,&p->q2,0,0,ti,t);
+ emit(f,"\t%s\t",s);
+ emit_obj(f,&p->z,t);
+ emit(f,",%s.0\n",regnames[ti]);
+ }else if(isesfrbit(z)&&!isesfrbit(q2)&&!isreg(q2)){
+ move(f,&p->q2,0,0,ti,t);
+ emit(f,"\textr\t#1\n");
+ emit(f,"\t%s\t",s);
+ emit_obj(f,&p->z,t);
+ emit(f,",%s.0\n",regnames[ti]);
+ }else{
+ if(isesfrbit(z)) emit(f,"\textr\t#1\n");
+ emit(f,"\t%s\t",s);
+ emit_obj(f,&p->z,t);emit(f,",");
+ emit_obj(f,&p->q2,t);emit(f,"\n");
+ }
+ continue;
+ }
+ if(c!=CONVERT) ierror(0);
+ }
+
+ if(c==TEST){
+ lastcomp=t;
+ if(p->ext.flags==EXT_IC_CMPIA){
+ if(p->ext.offset<0)
+ emit(f,"\tsub\t%s,#%ld\n",regnames[p->ext.r],-p->ext.offset);
+ else
+ emit(f,"\tadd\t%s,#%ld\n",regnames[p->ext.r],p->ext.offset);
+ cc=0;continue;
+ }
+ if(p->ext.flags==EXT_IC_CMPIB){
+ if(p->ext.offset<0)
+ emit(f,"\tcmpd%ld\t%s,#0\n",-p->ext.offset,regnames[p->ext.r]);
+ else
+ emit(f,"\tcmpi%ld\t%s,#0\n",p->ext.offset,regnames[p->ext.r]);
+ cc=0;continue;
+ }
+ if(cc&&(cc_t&NU)==(t&NU)&&compare_objects(cc,&p->q1)){
+ continue;
+ }
+ p->code=c=COMPARE;
+ gval.vmax=l2zm(0L);
+ p->q2.flags=KONST;
+ eval_const(&gval,MAXINT);
+ insert_const(&p->q2.val,t);
+ }
+ if(c==COMPARE&&isconst(q1)){
+ struct IC *p2;
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ p2=p->next;
+ while(p2&&p2->code==FREEREG) p2=p2->next;
+ if(!p2||p2->code<BEQ||p2->code>BGT) ierror(0);
+ if(p2->code==BLT) p2->code=BGT;
+ else if(p2->code==BGT) p2->code=BLT;
+ else if(p2->code==BLE) p2->code=BGE;
+ else if(p2->code==BGE) p2->code=BLE;
+ }
+ if(c==COMPARE&&p->ext.flags==EXT_IC_CMPIA){
+ long l;
+ if(!isconst(q2)) ierror(0);
+ eval_const(&p->q2.val,t);
+ l=zm2l(vmax);
+ if(p->ext.offset<0)
+ emit(f,"\tcmpd%ld\t%s,#%ld\n",-p->ext.offset,regnames[p->ext.r],l-p->ext.offset);
+ else
+ emit(f,"\tcmpi%ld\t%s,#%ld\n",p->ext.offset,regnames[p->ext.r],l-p->ext.offset);
+ cc=0;lastcomp=t;continue;
+ }
+ if(c==COMPARE&&p->ext.flags==EXT_IC_CMPIB){
+pric2(stdout,p);
+ if(p->ext.offset<0)
+ emit(f,"\tcmpd%ld\t%s,",-p->ext.offset,regnames[p->ext.r]);
+ else
+ emit(f,"\tcmpi%ld\t%s,",p->ext.offset,regnames[p->ext.r]);
+ emit_obj(f,&p->q2,t);emit(f,"\n");
+ cc=0;lastcomp=t;continue;
+ }
+ if(c==COMPARE&&isconst(q2)){
+ eval_const(&p->q2.val,t);
+ if(ISNULL()){
+ if(cc&&(cc_t&NU)==(t&NU)&&compare_objects(cc,&p->q1)){
+ lastcomp=t;continue;
+ }
+ }
+ }
+
+ if(c==SUBPFP){
+ p->code=c=SUB;
+ if((p->typf2&NQ)==NPOINTER) p->typf=t=INT;
+ else if((p->typf2&NQ)==HPOINTER) p->typf=t=LONG;
+ else ierror(0);
+ if((p->typf2&NQ)==NPOINTER){
+ cc=&p->z;cc_t=NPOINTER;
+ }else{
+ cc=0;
+ }
+ }
+
+ if(c==ADDI2P||c==SUBIFP){
+ /*if(c==ADDI2P) p->code=c=ADD; else p->code=c=SUB;*/
+ if((p->typf2&NQ)!=HPOINTER){
+ p->typf=t=(UNSIGNED|SHORT);
+ short_add=2;
+ if(isreg(q2)&®_pair(p->q2.reg,&rp)){
+ /*FIXME:warning*/
+ p->q2.reg=rp.r1;
+ }
+ }else if(ISHWORD(t)){
+ p->typf=t=(UNSIGNED|LONG);
+ short_add=1;
+ }
+ if((p->typf2&NQ)==NPOINTER){
+ cc=&p->z;cc_t=NPOINTER;
+ }else{
+ cc=0;
+ }
+ }
+ /* try to avoid z==q2 */
+ if((c==ADD||c==AND||c==OR||c==XOR||(c==ADDI2P&&!short_add))&&compare_objects(&p->q2,&p->z)){
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ }
+ /* DREFOBJs nach q2, um evtl. op reg,[ri] zu nutzen */
+ if(c==ADD||c==MULT||c==OR||c==AND||c==XOR){
+ if(isreg(q2)&&scratchreg(p->q2.reg,p)){
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ }
+ if((p->q1.flags&DREFOBJ)&&(!(p->q1.flags®)||p->q1.reg<=4)&&(!p->q1.am||p->q1.am->flags!=IMM_IND)){
+ if(!((p->q2.flags&DREFOBJ)&&(!p->q2.am||p->q2.am->flags!=IMM_IND))){
+ struct obj o;
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ }
+ }
+ }
+ /*FIXME: ICs mit mehreren Typen*/
+ if(switch_IC(p)&&isreg(z)){
+ reg=p->z.reg;
+ }else if(isreg(q1)&&(!ISLWORD(t)||reg_pair(p->q1.reg,&rp))&&(scratchreg(p->q1.reg,p)||(isreg(z)&&p->z.reg==p->q1.reg)||(!ISLWORD(t)&&c==COMPARE))){
+ reg=p->q1.reg;
+ }else{
+ if(ISLWORD(ztyp(p))){
+ tmp1=ti;tmp2=ti2;ti2_used=1;
+ BSET(regs_modified,ti);
+ BSET(regs_modified,ti2);
+ reg=MTMP1;
+ }else{
+ if((t&NQ)==CHAR){
+ BSET(regs_modified,tp);
+ reg=tp;
+ }else{
+ BSET(regs_modified,ti);
+ reg=ti;
+ }
+ }
+ }
+ /* op reg,mem/const */
+ if(issfr(z)&&(c==ADD||c==SUB||c==AND||c==OR||c==XOR||c==ADDI2P)&&(compare_objects(&p->q1,&p->z)||((c!=SUB&&c!=SUBIFP)&&compare_objects(&p->q2,&p->z)))){
+ char *s;
+ if(!compare_objects(&p->q1,&p->z)){o=p->q1;p->q1=p->q2;p->q2=o;}
+ if((p->q2.flags&(KONST|DREFOBJ))==KONST||((p->q2.flags&(VAR|DREFOBJ))==VAR&&ISSTATIC(p->q2.v))){
+ if(c>=OR&&c<=AND){
+ s=logicals[c-OR];
+ }else{
+ if(c==ADDI2P)
+ s=arithmetics[ADD-LSHIFT];
+ else if(c==SUBIFP)
+ s=arithmetics[SUB-LSHIFT];
+ else
+ s=arithmetics[c-LSHIFT];
+ }
+ if((p->q2.flags&VAR)&&ISFAR(p->q2.v)){
+ emit(f,"\texts\t#SEG ");isseg=1;emit_obj(f,&p->q2,t);emit(f,",#1\n");
+ }
+ emit(f,"\t%s%s\t",s,(t&NQ)==CHAR?"b":"");
+ emit_obj(f,&p->q1,t);
+ emit(f,",");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ cc=&p->z;cc_t=t;
+ continue;
+ }
+ }
+ /* op mem,reg */
+ if((c==ADD||c==SUB||c==AND||c==OR||c==XOR||c==ADDI2P)&&(compare_objects(&p->q1,&p->z)||((c!=SUB&&c!=SUBIFP)&&compare_objects(&p->q2,&p->z)))&&(p->z.flags&(VAR|VARADR|DREFOBJ|REG))==VAR&&ISSTATIC(p->z.v)){
+ char *s;
+ if(!compare_objects(&p->q1,&p->z)){o=p->q1;p->q1=p->q2;p->q2=o;}
+ cc=&p->z;cc_t=t;
+ if(isreg(q2)){
+ reg=p->q2.reg;
+ }else if(issfr(q2)){
+ reg=0;
+ }else if(isconst(q2)){
+ eval_const(&p->q2.val,t);
+ if(ISLWORD(t)){
+ unsigned long ul;
+ reg=MTMP1;
+ if((c==ADD||c==SUB||c==ADDI2P||c==SUBIFP)&&zumeqto(vumax,ul2zum(1UL))){
+ if(c==ADD) c=SUB;
+ else if(c==SUB) c=ADD;
+ else if(c==ADDI2P) c=SUBIFP;
+ else c=ADDI2P;
+ tmp1=ONES;tmp2=ONES;
+ }else{
+ ul=zum2ul(zumand(vumax,ul2zum(65535UL)));
+ if(ul==0) tmp1=ZEROS;
+ else if(ul==0xffff) tmp1=ONES;
+ else{
+ BSET(regs_modified,ti);
+ tmp1=ti;
+ emit(f,"\tmov\t%s,#%lu\n",regnames[ti],ul);
+ }
+ ul=zum2ul(zumand(zumrshift(vumax,ul2zum(16UL)),ul2zum(65535UL)));
+ if(ul==0) tmp2=ZEROS;
+ else if(ul==0xffff) tmp2=ONES;
+ else{
+ BSET(regs_modified,ti2);
+ tmp2=ti2;
+ emit(f,"\tmov\t%s,#%lu\n",regnames[ti2],ul);
+ }
+ }
+ }else{
+ long l;
+ if(c==OR&&(l=pof2(vumax))&&ISBADDR(p->z.v)){
+ emit(f,"\tbset\t");emit_obj(f,&p->z,t);
+ emit(f,".%ld\n",l-1);
+ cc=0;continue;
+ }else if(c==AND&&(l=pof2(zumkompl(vumax)))&&ISBADDR(p->z.v)){
+ emit(f,"\tbclr\t");emit_obj(f,&p->z,t);
+ emit(f,".%ld\n",l-1);
+ cc=0;continue;
+ }else if((c==ADD||c==SUB||c==ADDI2P||c==SUBIFP)&&zumeqto(vumax,ul2zum(1UL))){
+ if(c==ADD) c=SUB;
+ else if(c==SUB) c=ADD;
+ else if(c==ADDI2P) c=SUBIFP;
+ else c=ADDI2P;
+ reg=ONES;
+ }else{
+ if(zumeqto(vumax,ul2zum(0UL))) reg=ZEROS;
+ else if(zumeqto(vumax,ul2zum(0xffffUL))) reg=ONES;
+ else{
+ BSET(regs_modified,tp);
+ reg=tp;
+ move(f,&p->q2,0,0,reg,t);
+ }
+ }
+ }
+ }else{
+ /*FIXME:ones/zeros nutzen*/
+ if(ISLWORD(t)){
+ tmp1=ti;tmp2=ti2;
+ BSET(regs_modified,ti);
+ BSET(regs_modified,ti2);
+ reg=MTMP1;
+ }else{
+ BSET(regs_modified,tp);
+ reg=tp;
+ }
+ if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ){
+ if(ISLWORD(p->q2.dtyp)){
+ tmp3=ti2;tmp4=ti;
+ BSET(regs_modified,ti);
+ BSET(regs_modified,ti2);
+ p->q2.flags&=~DREFOBJ;
+ move(f,&p->q2,0,0,MTMP2,HPOINTER);
+ p->q2.flags=(REG|DREFOBJ);p->q2.reg=MTMP2;
+ }else if(!(p->q2.flags&KONST)){
+ BSET(regs_modified,ti);
+ move(f,&p->q2,0,0,ti,NPOINTER);
+ p->q2.flags=REG;p->q2.reg=ti;
+ }
+ }
+ move(f,&p->q2,0,0,reg,t);
+ }
+ if(c>=OR&&c<=AND){
+ s=logicals[c-OR];
+ }else{
+ if(c==ADDI2P)
+ s=arithmetics[ADD-LSHIFT];
+ else if(c==SUBIFP)
+ s=arithmetics[SUB-LSHIFT];
+ else
+ s=arithmetics[c-LSHIFT];
+ }
+ if(reg&®_pair(reg,&rp)){
+ if(ISFAR(p->z.v)){
+ emit(f,"\texts\t#SEG ");isseg=1;emit_obj(f,&p->z,t);emit(f,",#2\n");
+ }
+ emit(f,"\t%s\t",s);
+ emit_obj(f,&p->q1,t);emit(f,",%s\n",regnames[rp.r1]);
+ s=longcmd(s);
+ p->q1.val.vmax=zmadd(p->q1.val.vmax,l2zm(2L));
+ emit(f,"\t%s\t",s);
+ emit_obj(f,&p->q1,t);emit(f,",%s\n",regnames[rp.r2]);
+ p->q1.val.vmax=zmsub(p->q1.val.vmax,l2zm(2L));
+ }else{
+ if(ISFAR(p->z.v)){
+ emit(f,"\texts\t#SEG ");isseg=1;emit_obj(f,&p->z,t);emit(f,",#1\n");
+ }
+ emit(f,"\t%s%s\t",s,(t&NQ)==CHAR?"b":"");
+ emit_obj(f,&p->q1,t);
+ if(reg)
+ emit(f,",%s\n",((t&NQ)==CHAR&®<=MAXR)?bregnames[reg]:regnames[reg]);
+ else{
+ emit(f,",");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+ }
+ cc=&p->z;cc_t=t;
+ continue;
+ }
+ if(p->ext.flags==EXT_IC_BTST){
+ if(isreg(q1)){bit_reg=regnames[p->q1.reg];continue;}
+ if((p->q1.flags&(VAR|VARADR|DREFOBJ|REG))==VAR&&ISSTATIC(p->q1.v)&&ISBADDR(p->q1.v)){
+ bit_reg=0;bit_obj=&p->q1;
+ continue;
+ }
+ }
+
+ if((c==MULT||((c==DIV||c==MOD)&&(p->typf&UNSIGNED)))&&isconst(q2)){
+ long ln;
+ eval_const(&p->q2.val,t);
+ if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+ if(ln=pof2(vumax)){
+ if(c==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ p->code=AND;
+ }else{
+ vmax=l2zm(ln-1);
+ if(c==DIV) p->code=RSHIFT; else p->code=LSHIFT;
+ }
+ c=p->code;
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ if(c==AND){
+ insert_const(&p->q2.val,t);
+ }else{
+ insert_const(&p->q2.val,INT);
+ p->typf2=INT;
+ }
+ }
+ }
+ }
+ if(ISLWORD(t)&&(c==MULT||c==DIV||c==MOD)){
+ if(lib_larith(f,p)) continue;
+ }
+
+ if(!p->q1.am&&(p->q1.flags&DREFOBJ)){
+ if(!(p->q1.flags&(REG))){
+ if(ISLWORD(p->q1.dtyp)){
+ tmp3=ti2;tmp4=ti;ti2_used=1;
+ BSET(regs_modified,ti);
+ BSET(regs_modified,ti2);
+ p->q1.flags&=~DREFOBJ;
+ move(f,&p->q1,0,0,MTMP2,FPOINTER);
+ p->q1.reg=MTMP2;
+ p->q1.flags=(REG|DREFOBJ);
+ }else if(!(p->q1.flags&KONST)){
+ BSET(regs_modified,ti);
+ p->q1.flags&=~DREFOBJ;
+ move(f,&p->q1,0,0,ti,NPOINTER);
+ p->q1.reg=ti;
+ p->q1.flags=(REG|DREFOBJ);
+ }
+ }
+ if(p->q2.flags){
+ move(f,&p->q1,0,0,reg,q2typ(p));/*FIXME*/
+ if((!isreg(q1)||p->q1.reg!=reg)&&c==COMPARE&&!ISLWORD(t)&&isconst(q2)){
+ /* avoid cmp, if not needed */
+ eval_const(&p->q2.val,t);
+ if(ISNULL()){
+ lastcomp=t;continue;
+ }
+ }
+ }
+ }else{
+ if(p->q2.flags){
+ move(f,&p->q1,0,0,reg,q1typ(p));/*FIXME*/
+ if((!isreg(q1)||p->q1.reg!=reg)&&c==COMPARE&&!ISLWORD(t)&&isconst(q2)){
+ /* avoid cmp, if not needed */
+ eval_const(&p->q2.val,t);
+ if(ISNULL()){
+ lastcomp=t;continue;
+ }
+ }
+ }
+ }
+ if(p->ext.flags==EXT_IC_BTST){ bit_reg=regnames[reg];continue;}
+ if(!p->q2.am&&(p->q2.flags&DREFOBJ)){
+ if(!(p->q2.flags&(REG))||p->q2.reg>4){
+ if(ISLWORD(p->q2.dtyp)){
+ if(ti2_used) tmp4=get_reg(f,p); else tmp4=ti2;
+ tmp3=tp;
+ BSET(regs_modified,tmp3);
+ BSET(regs_modified,tmp4);
+ p->q2.flags&=~DREFOBJ;
+ move(f,&p->q2,0,0,MTMP2,FPOINTER);
+ p->q2.reg=MTMP2;
+ p->q2.flags=(REG|DREFOBJ);
+ }else if(!(p->q2.flags&KONST)){
+ BSET(regs_modified,tp);
+ p->q2.flags&=~DREFOBJ;
+ move(f,&p->q2,0,0,tp,NPOINTER);
+ p->q2.flags=(REG|DREFOBJ);
+ p->q2.reg=tp;
+ }
+ }
+ }
+ if(c==CONVERT&&!must_convert(p->typf,p->typf2,0)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[p->typf&NQ];
+ }
+
+ if(c==CONVERT){
+ int to=p->typf2&NU;
+ if(to==INT) to=SHORT;
+ if(to==(UNSIGNED|INT)||to==NPOINTER) to=(UNSIGNED|SHORT);
+ if(to==FPOINTER||to==HPOINTER) to=(UNSIGNED|LONG);
+ if((t&NU)==INT) t=SHORT;
+ if((t&NU)==(UNSIGNED|INT)||(t&NU)==NPOINTER) t=(UNSIGNED|SHORT);
+ if((t&NQ)==FPOINTER||(t&NQ)==HPOINTER) t=(UNSIGNED|LONG);
+ if((to&NQ)<=LONG&&(t&NQ)<=LONG){
+ if((to&NQ)<=(t&NQ)){
+ if((to&NQ)==(t&NQ)) ierror(0);
+ if((to&NQ)==BIT){
+ cc=0;
+ if((p->q1.flags&(VAR|REG|DREFOBJ|VARADR))!=VAR||!ISSTATIC(p->q1.v)) ierror(0);
+ if(reg_pair(reg,&rp)){
+ emit(f,"\tmov\t%s,#0\n",regnames[rp.r1]);
+ emit(f,"\tmov\t%s,#0\n",regnames[rp.r2]);
+ emit(f,"\tbmov\t%s.0,",regnames[rp.r1]);
+ emit_obj(f,&p->q1,t);emit(f,"\n");
+ }else{
+ emit(f,"\tmov\t%s,#0\n",regnames[reg]);
+ emit(f,"\tbmov\t%s.0,",regnames[reg]);
+ }
+ emit_obj(f,&p->q1,t);emit(f,"\n");
+ save_result(f,reg,p,t);
+ continue;
+ }
+ if((p->q1.flags&(VAR|REG|VARADR))==VAR&&ISSTATIC(p->q1.v)&&ISFAR(p->q1.v)){
+ emit(f,"\texts\t#SEG ");isseg=1;emit_obj(f,&p->q1,t);
+ emit(f,",#1\n");
+ }
+ qp.SEG=0;
+ if(!p->q1.am&&(p->q1.flags&DREFOBJ)&®_pair(p->q1.reg,&qp))
+ emit(f,"\texts\t%s,#1\n",regnames[qp.SEG]);
+ if(p->q1.am&®_pair(p->q1.am->base,&qp))
+ emit(f,"\texts\t%s,#1\n",regnames[qp.SEG]);
+ if(reg_pair(reg,&rp)){
+ cc=0;
+ if((to&NQ)==CHAR){
+ if(isreg(q1)||((p->q1.flags&(VAR|VARADR|DREFOBJ))==VAR&&ISSTATIC(p->q1.v))){
+ emit(f,"\tmovb%c\t%s,",(to&UNSIGNED)?'z':'s',regnames[rp.r1]);
+ if((to&NQ)==CHAR&&isreg(q1)) emit(f,"%s",bregnames[p->q1.reg]);
+ else if(qp.SEG) emit(f,"[%s]",regnames[qp.SOF]);
+ else emit_obj(f,&p->q1,to);
+ emit(f,"\n");
+ }else{
+ BSET(regs_modified,tp);
+ emit(f,"\tmovb\t%s,",bregnames[tp]);
+ if(isreg(q1)) emit(f,"%s",bregnames[p->q1.reg]);
+ else if(!p->q1.am&&qp.SEG) emit(f,"[%s]",regnames[qp.SOF]);
+ else emit_obj(f,&p->q1,to);
+ emit(f,"\n");
+ emit(f,"\tmovb%c\t%s,%s\n",(to&UNSIGNED)?'z':'s',regnames[rp.r1],bregnames[tp]);
+ }
+ }else{
+ emit(f,"\tmov\t%s,",regnames[rp.r1]);
+ if(qp.SEG) emit(f,"[%s]",regnames[qp.SOF]);
+ else emit_obj(f,&p->q1,to);
+ emit(f,"\n");
+ }
+ if(to&UNSIGNED)
+ emit(f,"\tmov\t%s,#0\n",regnames[rp.r2]);
+ else
+ emit(f,"\tmov\t%s,%s\n\tashr\t%s,#15\n",regnames[rp.r2],regnames[rp.r1],regnames[rp.r2]);
+
+ }else{
+ cc=&p->z;cc_t=t;
+ if(isreg(q1)||((p->q1.flags&(VAR|VARADR|DREFOBJ))==VAR&&ISSTATIC(p->q1.v))){
+ emit(f,"\tmovb%c\t%s,",(to&UNSIGNED)?'z':'s',regnames[reg]);
+ if((to&NQ)==CHAR&&isreg(q1)) emit(f,"%s",bregnames[p->q1.reg]);
+ else if(qp.SEG) emit(f,"[%s]",regnames[qp.SOF]);
+ else emit_obj(f,&p->q1,to);
+ emit(f,"\n");
+ }else{
+ BSET(regs_modified,tp);
+ emit(f,"\tmovb\t%s,",bregnames[tp]);
+ if(isreg(q1)) emit(f,"%s",bregnames[p->q1.reg]);
+ else if(!p->q1.am&&qp.SEG) emit(f,"[%s]",regnames[qp.SOF]);
+ else emit_obj(f,&p->q1,to);
+ emit(f,"\n");
+ emit(f,"\tmovb%c\t%s,%s\n",(to&UNSIGNED)?'z':'s',regnames[reg],bregnames[tp]);
+ }
+ }
+ save_result(f,reg,p,t);
+ continue;
+ }else{
+ if((t&NQ)==BIT){
+ if(!isreg(z)&&((p->z.flags&(VAR|REG|DREFOBJ|VARADR))!=VAR||!ISSTATIC(p->z.v))) ierror(0);
+ if(isreg(q1)){
+ reg=p->q1.reg;
+ }else{
+ if(ISLWORD(to)){
+ tmp1=ti;tmp2=ti2;
+ BSET(regs_modified,ti);
+ BSET(regs_modified,ti2);
+ reg=MTMP1;
+ }
+ }
+ move(f,&p->q1,0,0,reg,to);
+ if(reg_pair(reg,&rp)){
+ if(isreg(q1)&&!scratchreg(reg,p)){
+ BSET(regs_modified,ti);
+ emit(f,"\tmov\t%s,%s\n",regnames[ti],regnames[rp.r1]);
+ emit(f,"\tor\t%s,%s\n",regnames[ti],regnames[rp.r2]);
+ }else
+ emit(f,"\tor\t%s,%s\n",regnames[rp.r1],regnames[rp.r2]);
+ }else{
+ if(isreg(q1)) emit(f,"\tcmp%s\t%s,#0\n",(to&NQ)==CHAR?"b":"",(to&NQ)==CHAR?bregnames[reg]:regnames[reg]);
+ }
+ emit(f,"\tbmovn\t");
+ if(isesfrbit(z))
+ emit(f,"%s.0",regnames[ti]);
+ else
+ emit_obj(f,&p->z,t);
+ emit(f,",PSW.3\n");
+ if(isesfrbit(z)){
+ emit(f,"\textr\t#1\n");
+ emit(f,"\tbmov\t");
+ emit_obj(f,&p->z,t);
+ emit(f,",%s.0\n",regnames[ti]);
+ }
+ cc=0;continue;
+ }
+ cc=&p->z;cc_t=t;
+ if(ISLWORD(to)){
+ if(isreg(q1)) {reg_pair(p->q1.reg,&rp);p->q1.reg=rp.r1;}
+ to=SHORT;
+ }
+ if(isreg(q1)&®ok(p->q1.reg,t,0)) reg=p->q1.reg;
+ if(isreg(z)) reg=p->z.reg;
+ if(!regok(reg,t,0)){
+ reg=tp;
+ BSET(regs_modified,tp);
+ }
+ move(f,&p->q1,0,0,reg,to);
+ save_result(f,reg,p,t);
+ }
+ continue;
+ }
+ ierror(0);
+ }
+ if(c==MINUS||c==KOMPLEMENT){
+ move(f,&p->q1,0,0,reg,t);
+ if(reg_pair(reg,&rp)){
+ emit(f,"\t%s\t%s\n",(c==MINUS?"neg":"cpl"),regnames[rp.r1]);
+ if(c==MINUS) emit(f,"\taddc\t%s,#0\n",regnames[rp.r2]);
+ emit(f,"\t%s\t%s\n",(c==MINUS?"neg":"cpl"),regnames[rp.r2]);
+ cc=0;
+ }else{
+ emit(f,"\t%s%s\t%s\n",(c==MINUS?"neg":"cpl"),x_t[t&NQ],regnames[reg]);
+ cc=&p->z;cc_t=t;
+ }
+ save_result(f,reg,p,t);
+ continue;
+ }
+ if(c==SETRETURN){
+ if(p->z.reg){
+ move(f,&p->q1,0,0,p->z.reg,t);
+ BSET(regs_modified,p->z.reg);
+ }
+ cc=0; /* probably not needed */
+ continue;
+ }
+ if(c==GETRETURN){
+ if(p->q1.reg){
+ if(!isreg(z)||p->z.reg!=p->q1.reg){ cc=&p->z;cc_t=t;}
+ save_result(f,p->q1.reg,p,t);
+ }
+ continue;
+ }
+ if(c==CALL){
+ int reg,jmp=0;long csstack=0,custack=0;
+ cc=0;
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+ long va_off=loff-usrstackoffset+pushedsize+zm2l(va_offset(v));
+ emit(f,"\tmov\t%s,%s\n",regnames[r4],regnames[sp]);
+ if(va_off)
+ emit(f,"\tadd\t%s,#%ld\n",regnames[r4],va_off);
+ BSET(regs_modified,r4);
+ if(LARGE||HUGE){
+ emit(f,"\tmov\t%s,#0\n",regnames[r5]);
+ BSET(regs_modified,r5);
+ }
+ continue;
+ }
+ if(stack_valid){
+ int i;
+ if(p->call_cnt<=0){
+ err_ic=p;if(f) error(320);
+ stack_valid=0;
+ }
+ for(i=0;stack_valid&&i<p->call_cnt;i++){
+ if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_STACK)){
+ if(p->call_list[i].v->fi->stack1>custack) custack=p->call_list[i].v->fi->stack1;
+ if(p->call_list[i].v->fi->stack2>csstack) csstack=p->call_list[i].v->fi->stack2;
+ }else{
+ err_ic=p;if(f) error(317,p->call_list[i].v->identifier);
+ stack_valid=0;
+ }
+ }
+ }
+ if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS;
+ if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ callee_push(custack,csstack);
+ }else{
+ if(usrstackoffset==0&&!have_frame&&!(v->tattr&INTERRUPT)){
+ struct IC *p2;
+ jmp=1;
+ for(p2=p->next;p2;p2=p2->next){
+ if(p2->code!=FREEREG&&p2->code!=ALLOCREG&&p2->code!=LABEL&&
+ (p2->code!=GETRETURN||(p2->z.flags&(REG|DREFOBJ))!=REG||p2->q1.reg!=p2->z.reg)&&
+ (p2->code!=SETRETURN||(p2->q1.flags&(REG|DREFOBJ))!=REG||p2->q1.reg!=p2->z.reg)){
+ jmp=0;break;
+ }
+ }
+ }
+ if(p->q1.flags&DREFOBJ){
+ int clabel=++label;
+ if(ISLWORD(p->q1.dtyp)){
+ int tmp;
+ if(!ti2_used) tmp=ti2; else tmp=tp;
+ BSET(regs_modified,tmp);
+ emit(f,"\tmov\t%s,#SEG %s%d\n",regnames[tmp],labprefix,clabel);
+ emit(f,"\tpush\t%s\n",regnames[tmp]);
+ emit(f,"\tmov\t%s,#SOF %s%d\n",regnames[tmp],labprefix,clabel);
+ emit(f,"\tpush\t%s\n",regnames[tmp]);
+ push(0,4);
+ }
+ if(!(p->q1.flags®)) ierror(0);
+ reg=p->q1.reg;
+ p->q1.flags&=~DREFOBJ;
+ if(!ISLWORD(p->q1.dtyp)){
+ emit(f,"\tcalli\tcc_uc,[%s]\n",regnames[reg]);
+ push(0,2);
+ callee_push(custack,csstack);
+ pop(0,2);
+ }else{
+ if(!reg_pair(reg,&rp)) ierror(0);
+ emit(f,"\tpush\t%s\n",regnames[rp.r2]);
+ emit(f,"\tpush\t%s\n",regnames[rp.r1]);
+ push(0,4);
+ callee_push(custack,csstack);
+ emit(f,"\trets\n");
+ emit(f,"%s%d:\n",labprefix,clabel);
+ pop(0,8);
+ }
+ }else{
+ if(jmp){
+ emit(f,"\t%s",jump);
+ if(!need_return) ret=TASKING?"retv":"";
+ callee_push(custack,csstack);
+ }else{
+ emit(f,"\t%s\t",call);
+ if(TINY)
+ push(0,2);
+ else
+ push(0,4);
+ callee_push(custack,csstack);
+ if(TINY)
+ pop(0,2);
+ else
+ pop(0,4);
+ }
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ }
+ if(!zmeqto(l2zm(0L),p->q2.val.vmax)){
+ notpopped+=zm2l(p->q2.val.vmax);
+ dontpop-=zm2l(p->q2.val.vmax);
+ if(!(g_flags[2]&USEDFLAG)&&usrstackoffset==-notpopped){
+ /* Entfernen der Parameter verzoegern */
+ }else{
+ emit(f,"\tadd\t%s,#%ld\n",regnames[sp],zm2l(p->q2.val.vmax));
+ pop(zm2l(p->q2.val.vmax),0);
+ notpopped-=zm2l(p->q2.val.vmax);cc=0;
+ }
+ }
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax);
+ if(!ISSCALAR(t)||!zmeqto(p->q2.val.vmax,sizetab[t&NQ])||!zmleq(p->q2.val.vmax,l2zm(4L))){
+ int alq,alz,rq,rz;unsigned long size;
+ cc=0;
+ size=zm2l(p->q2.val.vmax);
+ /*FIXME: check for (s)huge */
+ if(malign[t&NQ]==1){
+ alq=alignment(&p->q1);
+ alz=alignment(&p->z);
+ }else{
+ alq=alz=0;
+ }
+ if(size==1||(size==2&&alq==0&&alz==0)){
+ if(c==PUSH&&zm2l(p->z.val.vmax)==1){
+ emit(f,"\tsub\t%s,#1\n",regnames[sp]);
+ push(1,0);size=1;
+ }
+ BSET(regs_modified,tp);
+ move(f,&p->q1,0,0,tp,size==1?CHAR:SHORT);
+ if(c==PUSH){
+ emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[tp]);
+ push(size,0);
+ }else
+ save_result(f,tp,p,size==1?CHAR:SHORT);
+ continue;
+ }
+ if(size==4&&alq==0&&alz==0){
+ tmp1=ti;tmp2=ti2;
+ BSET(regs_modified,ti);
+ BSET(regs_modified,ti2);
+ move(f,&p->q1,0,0,MTMP1,LONG);
+ if(c==PUSH){
+ emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[tmp2]);
+ emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[tmp1]);
+ push(4,0);
+ }else
+ save_result(f,MTMP1,p,LONG);
+ continue;
+ }
+ if(p->q1.am){
+ if(p->q1.am->flags!=IMM_IND) ierror(0);
+ if(!scratchreg(p->q1.am->base,p)){
+ BSET(regs_modified,ti);
+ emit(f,"\tmov\t%s,%s\n",regnames[ti],regnames[p->q1.am->base]);
+ rq=ti;
+ }else
+ rq=p->q1.am->base;
+ emit(f,"\tadd\t%s,#%ld",regnames[rq],p->q1.am->offset);
+ if(p->q1.am->v){
+ if(p->q1.am->v->storage_class==EXTERN)
+ emit(f,"+%s%s\n",idprefix,p->q1.am->v->identifier);
+
+ else
+ emit(f,"+%s%ld\n",labprefix,zm2l(p->q1.am->v->offset));
+ }
+ emit(f,"\n");
+ }else if(p->q1.flags®){
+ if(scratchreg(p->q1.reg,p)){
+ rq=p->q1.reg;
+ }else{
+ BSET(regs_modified,ti);
+ emit(f,"\tmov\t%s,%s\n",regnames[ti],regnames[p->q1.reg]);
+ rq=ti;
+ }
+ }else if((p->q1.flags&VAR)&&ISSTATIC(p->q1.v)){
+ int m=p->q1.flags;
+ rq=ti;
+ BSET(regs_modified,ti);
+ if(p->q1.flags&DREFOBJ)
+ p->q1.flags&=~DREFOBJ;
+ else
+ p->q1.flags|=VARADR;
+ move(f,&p->q1,0,0,ti,NPOINTER);
+ p->q1.flags&=~VARADR;
+ }else{
+ BSET(regs_modified,ti);
+ rq=ti;
+ emit(f,"\tmov\t%s,%s\n",regnames[ti],regnames[sp]);
+ if(voff(&p->q1))
+ emit(f,"\tadd\t%s,#%ld\n",regnames[ti],voff(&p->q1));
+ }
+ if(!p->z.flags){
+ /* PUSH */
+ emit(f,"\tsub\t%s,#%lu\n",regnames[sp],size);
+ emit(f,"\tmov\t%s,%s\n",regnames[ti2],regnames[sp]);
+ rz=ti2;
+ push(size,0);
+ BSET(regs_modified,ti2);
+ }else if(p->z.am){
+ if(p->z.am->flags!=IMM_IND) ierror(0);
+ if(!scratchreg(p->z.am->base,p)){
+ BSET(regs_modified,ti2);
+ emit(f,"\tmov\t%s,%s\n",regnames[ti2],regnames[p->z.am->base]);
+ rz=ti2;
+ }else
+ rz=p->z.am->base;
+ emit(f,"\tadd\t%s,#%ld",regnames[rz],p->z.am->offset);
+ if(p->z.am->v){
+ if(p->z.am->v->storage_class==EXTERN)
+ emit(f,"+%s%s",idprefix,p->z.am->v->identifier);
+ else
+ emit(f,"%+s%ld",labprefix,zm2l(p->z.am->v->offset));
+
+ }
+ emit(f,"\n");
+ }else if(p->z.flags®){
+ if(scratchreg(p->z.reg,p)){
+ rz=p->z.reg;
+ }else{
+ BSET(regs_modified,ti2);
+ emit(f,"\tmov\t%s,%s\n",regnames[ti2],regnames[p->z.reg]);
+ rz=ti2;
+ }
+ }else if(ISSTATIC(p->z.v)){
+ int m=p->z.flags;
+ rz=ti2;
+ BSET(regs_modified,ti2);
+ if(p->z.flags&DREFOBJ)
+ p->z.flags&=~DREFOBJ;
+ else
+ p->z.flags|=VARADR;
+ move(f,&p->z,0,0,ti2,NPOINTER);
+ p->z.flags=m;
+ }else{
+ BSET(regs_modified,ti2);
+ rz=ti2;
+ emit(f,"\tmov\t%s,%s\n",regnames[ti2],regnames[sp]);
+ if(voff(&p->z))
+ emit(f,"\tadd\t%s,#%ld\n",regnames[ti2],voff(&p->z));
+ }
+ if(alq==0&&alz==0){
+ if(optspeed){
+ if((size/8)>1){
+ BSET(regs_modified,tp);
+ emit(f,"\tmov\t%s,#%lu\n",regnames[tp],size/8);
+ emit(f,"%s%d:\n",labprefix,++label);
+ }
+ if(size>=8){
+ emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+ emit(f,"\tadd\t%s,#2\n",regnames[rz]);
+ emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+ emit(f,"\tadd\t%s,#2\n",regnames[rz]);
+ emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+ emit(f,"\tadd\t%s,#2\n",regnames[rz]);
+ emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+ emit(f,"\tadd\t%s,#2\n",regnames[rz]);
+ }
+ if((size/8)>1){
+ emit(f,"\tsub\t%s,#1\n",regnames[tp]);
+ emit(f,"\tjmpr\tcc_nz,%s%d\n",labprefix,label);
+ }
+ size&=7;
+ if(size>=4){
+ emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+ emit(f,"\tadd\t%s,#2\n",regnames[rz]);
+ emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+ if(size>4) emit(f,"\tadd\t%s,#2\n",regnames[rz]);
+ }
+ size&=3;
+ if(size>=2){
+ emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+ if(size>2) emit(f,"\tadd\t%s,#2\n",regnames[rz]);
+ }
+ if(size&1)
+ if(size&1) emit(f,"\tmovb\t[%s],[%s]\n",regnames[rz],regnames[rq]);
+ }else{
+ BSET(regs_modified,tp);
+ emit(f,"\tmov\t%s,#%lu\n",regnames[tp],size/2);
+ emit(f,"%s%d:\n",labprefix,++label);
+ emit(f,"\tmov\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+ emit(f,"\tadd\t%s,#2\n",regnames[rz]);
+ emit(f,"\tsub\t%s,#1\n",regnames[tp]);
+ emit(f,"\tjmpr\tcc_nz,%s%d\n",labprefix,label);
+ if(size&1) emit(f,"\tmovb\t[%s],[%s]\n",regnames[rz],regnames[rq]);
+ }
+ }else{
+ BSET(regs_modified,tp);
+ emit(f,"\tmov\t%s,#%lu\n",regnames[tp],size);
+ emit(f,"%s%d:\n",labprefix,++label);
+ emit(f,"\tmovb\t[%s],[%s+]\n",regnames[rz],regnames[rq]);
+ emit(f,"\tadd\t%s,#1\n",regnames[rz]);
+ emit(f,"\tsub\t%s,#1\n",regnames[tp]);
+ emit(f,"\tjmpr\tcc_nz,%s%d\n",labprefix,label);
+ }
+ continue;
+ }
+ /* mov [rx],[ry] ; mov [rx+],[ry] ; mov [rx],[ry+] */
+ if(!ISLWORD(t)&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&(!p->z.am||p->z.am->flags==POST_INC)&&(!p->q1.am||p->q1.am->flags==POST_INC)&&!reg_pair(p->q1.reg,&rp)&&!reg_pair(p->z.reg,&rp)){
+ emit(f,"\tmov%s\t",(t&NQ)==CHAR?"b":"");
+ emit_obj(f,&p->z,t);emit(f,",");
+ emit_obj(f,&p->q1,t);emit(f,"\n");
+ cc=&p->z;cc_t=t;continue;
+ }
+ /* mov mem,[rx]/reg */
+ if(!ISLWORD(t)&&(issfr(q1)||(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ))&&(p->z.flags&(REG|DREFOBJ|VAR))==VAR&&!p->q1.am&&(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)){
+ emit(f,"\tmov%s\t",(t&NQ)==CHAR?"b":"");
+ emit_obj(f,&p->z,t);emit(f,",");
+ emit_obj(f,&p->q1,t);emit(f,"\n");
+ cc=&p->z;cc_t=t;continue;
+ }
+ /* mov [rx]/reg,mem */
+ if(!ISLWORD(t)&&(issfr(z)||(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ))&&(p->q1.flags&(REG|DREFOBJ|VAR))==VAR&&!p->z.am&&(p->q1.v->storage_class==STATIC||p->q1.v->storage_class==EXTERN)){
+ emit(f,"\tmov%s\t",(t&NQ)==CHAR?"b":"");
+ emit_obj(f,&p->z,t);emit(f,",");
+ emit_obj(f,&p->q1,t);emit(f,"\n");
+ cc=&p->z;cc_t=t;continue;
+ }
+ /* mov reg,op */
+ if(issfr(z)&&(p->q1.flags&KONST)){
+ emit(f,"\tmov%s\t",(t&NQ)==CHAR?"b":"");
+ emit_obj(f,&p->z,t);emit(f,",");
+ emit_obj(f,&p->q1,t);emit(f,"\n");
+ cc=&p->z;cc_t=t;continue;
+ }
+
+ if(isreg(q1)){
+ reg=p->q1.reg;
+ }else if(isreg(z)){
+ reg=p->z.reg;
+ }else{
+ BSET(regs_modified,ti);
+ if(ISLWORD(t)){
+ BSET(regs_modified,ti2);
+ tmp1=ti;tmp2=ti2;
+ reg=MTMP1;
+ }else
+ reg=ti;
+ }
+ if(c==PUSH){
+ move(f,&p->q1,0,0,reg,t);
+ if(reg_pair(reg,&rp)){
+ emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[rp.r2]);
+ emit(f,"\tmov\t[-%s],%s\n",regnames[sp],regnames[rp.r1]);
+ cc=0;
+ }else{
+ emit(f,"\tmov%s\t[-%s],%s\n",x_t[t&NQ],regnames[sp],regnames[reg]);
+ cc=&p->q1;cc_t=t;
+ }
+ push(zm2l(p->z.val.vmax),0);
+ continue;
+ }
+ if(c==ASSIGN){
+ if((p->z.flags&(VAR|REG|DREFOBJ))==VAR&&ISSTATIC(p->z.v)&&isconst(q1)){
+ /*FIXME: long und ones */
+ eval_const(&p->q1.val,t);
+ if(ISNULL()&&!ISLWORD(t)){
+ emit(f,"\tmov%s\t",(t&NQ)==CHAR?"b":"");emit_obj(f,&p->z,t);
+ emit(f,",ZEROS\n");
+ cc=&p->z;cc_t=t;continue;
+ }
+ }
+ if((t&NQ)==CHAR&&!regok(reg,CHAR,0)){
+ reg=tp;
+ BSET(regs_modified,tp);
+ }
+ move(f,&p->q1,0,0,reg,t);
+ save_result(f,reg,p,t);
+ if(ISLWORD(t)){
+ cc=0;
+ }else{
+ cc=&p->z;cc_t=t;
+ }
+ continue;
+ }
+ ierror(0);
+ }
+ if(c==ADDRESS){
+ if(reg_pair(reg,&rp)){
+ emit(f,"\tmov\t%s,%s\n",regnames[rp.r1],regnames[sp]);
+ emit(f,"\tmov\t%s,#0\n",regnames[rp.r2]);
+ if(voff(&p->q1))
+ emit(f,"\tadd\t%s,#%ld\n",regnames[rp.r1],voff(&p->q1)&0xffff);
+ }else{
+ emit(f,"\tmov\t%s,%s\n",regnames[reg],regnames[sp]);
+ if(voff(&p->q1)) emit(f,"\tadd\t%s,#%ld\n",regnames[reg],voff(&p->q1));
+ }
+ save_result(f,reg,p,p->typf2);
+ cc=0;
+ continue;
+ }
+
+ if(c==MOD||c==DIV){
+ if(ISLWORD(t)) ierror(0);
+ /*FIXME:suboptimal*/
+ emit(f,"\tmov\tMDL,%s\n",regnames[reg]);
+ move(f,&p->q2,0,0,reg,t);
+ emit(f,"\tdiv%s\t%s\n",(t&UNSIGNED)?"u":"",regnames[reg]);
+ if(c==MOD)
+ emit(f,"\tmov\t%s,MDH\n",regnames[reg]);
+ else
+ emit(f,"\tmov\t%s,MDL\n",regnames[reg]);
+ save_result(f,reg,p,t);
+ cc=&p->z;cc_t=t;
+ continue;
+ }
+ if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==COMPARE||c==ADDI2P||c==SUBIFP){
+ char *s;
+ /*FIXME: nicht immer besser*/
+/* rfi: better performed in LSHIFT code generation
+ if(ISLWORD(t)&&c==LSHIFT&&isconst(q2)){
+ eval_const(&p->q2.val,t);
+ if(zm2l(vmax)==1&&!p->q1.am){
+ p->code=c=ADD;
+ p->q2=p->q1;
+ }
+ }
+*/
+ if(ISLWORD(t)&&c==MULT) ierror(0);
+ if(ISLWORD(t)&&(c==LSHIFT||c==RSHIFT)){
+/* rfi: we now handle constant value greater than 16 in const shift generation
+ if(isconst(q2))
+ eval_const(&p->q2.val,q2typ(p));
+ if(!isconst(q2)||zmleq(l2zm(16L),vmax)){
+*/
+ if(!isconst(q2)){
+ int cnt,lab1,lab2;
+ if(isreg(q2)&&scratchreg(p->q2.reg,p)){
+ cnt=p->q2.reg;
+ }else{
+ BSET(regs_modified,tp);
+ cnt=tp;
+ if(isreg(q2)&®_pair(p->q2.reg,&rp))
+ move(f,0,rp.r1,0,tp,INT);
+ else
+ move(f,&p->q2,0,0,tp,INT);
+ }
+ if(reg_pair(cnt,&rp))
+ cnt=rp.r1;
+ /*move(f,&p->q1,0,0,reg,ztyp(p));*/
+ lab1=++label;lab2=++label;
+ if(!reg_pair(reg,&rp)) ierror(0);
+ if(c==LSHIFT){
+ emit(f,"\tjmpr\tcc_uc,%s%d\n",labprefix,lab2);
+ emit(f,"%s%d:\n",labprefix,lab1);
+ emit(f,"\tadd\t%s,%s\n",regnames[rp.r1],regnames[rp.r1]);
+ emit(f,"\taddc\t%s,%s\n",regnames[rp.r2],regnames[rp.r2]);
+ emit(f,"%s%d:\n",labprefix,lab2);
+/* rfi: fix off by one and handle negative shift value
+ emit(f,"\tsub\t%s,#1\n",regnames[cnt]);
+ emit(f,"\tjmpr\tcc_ne,%s%d\n",labprefix,lab1);
+*/
+ emit(f,"\tcmpd1\t%s,#1\n",regnames[cnt]);
+ emit(f,"\tjmpr\tcc_sge,%s%d\n",labprefix,lab1);
+ }else{
+ emit(f,"\tjmpr\tcc_uc,%s%d\n",labprefix,lab2);
+ emit(f,"%s%d:\n",labprefix,lab1);
+ emit(f,"\tshr\t%s,#1\n",regnames[rp.r1]);
+ emit(f,"\tbmov\t%s.15,%s.0\n",regnames[rp.r1],regnames[rp.r2]);
+/* rfi: use ashr for signed shift
+ emit(f,"\tshr\t%s,#1\n",regnames[rp.r2]);
+*/
+ emit(f,"\t%sshr\t%s,#1\n",(t&UNSIGNED)?"":"a",regnames[rp.r2]);
+ emit(f,"%s%d:\n",labprefix,lab2);
+/* rfi: fix off by one and handle negative shift value
+ emit(f,"\tsub\t%s,#1\n",regnames[cnt]);
+ emit(f,"\tjmpr\tcc_ne,%s%d\n",labprefix,lab1);
+*/
+ emit(f,"\tcmpd1\t%s,#1\n",regnames[cnt]);
+ emit(f,"\tjmpr\tcc_sge,%s%d\n",labprefix,lab1);
+ }
+ save_result(f,reg,p,ztyp(p));
+ continue;
+ }
+ }
+ if(c>=OR&&c<=AND){
+ s=logicals[c-OR];
+ }else{
+ if(c==ADDI2P)
+ s=arithmetics[ADD-LSHIFT];
+ else if(c==SUBIFP)
+ s=arithmetics[SUB-LSHIFT];
+ else
+ s=arithmetics[c-LSHIFT];
+ }
+ if(c==RSHIFT&&!(t&UNSIGNED)) s="ashr";
+ if(c==COMPARE){
+ lastcomp=t;
+ if(ISLWORD(t)) s="sub"; else s="cmp";
+ }
+ if((c==MULT&&!isreg(q2))){
+ BSET(regs_modified,tp);
+ move(f,&p->q2,0,0,tp,t);
+ p->q2.flags=REG;
+ p->q2.reg=tp;
+ }
+ if((c==LSHIFT||c==RSHIFT)&&!isconst(q2)&&!isreg(q2)){
+ BSET(regs_modified,tp);
+ move(f,&p->q2,0,0,tp,t);
+ p->q2.flags=REG;
+ p->q2.reg=tp;
+ }
+ if(isreg(q2)){
+ if(reg_pair(reg,&rp)){
+ if(!reg_pair(p->q2.reg,&qp)) qp.r1=p->q2.reg;
+ emit(f,"\t%s\t%s,%s\n",s,regnames[rp.r1],regnames[qp.r1]);
+ s=longcmd(s);
+ if(!short_add) emit(f,"\t%s\t%s,%s\n",s,regnames[rp.r2],regnames[qp.r2]);
+ }else{
+ emit(f,"\t%s%s\t%s,%s\n",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg],(t&NQ)==CHAR?bregnames[p->q2.reg]:regnames[p->q2.reg]);
+ }
+ }else if(p->q2.am){
+ if(reg_pair(p->q2.am->base,&rp)){
+ int seg=rp.SEG;
+ if(!short_add&®_pair(reg,&rp))
+ emit(f,"\texts\t%s,#3\n",regnames[seg]);
+ else
+ emit(f,"\texts\t%s,#1\n",regnames[seg]);
+ }
+ if(reg_pair(reg,&rp)){
+ BSET(regs_modified,tp);
+ emit(f,"\tmov\t%s,",regnames[tp]);emit_obj(f,&p->q2,t);emit(f,"\n");
+ emit(f,"\t%s\t%s,%s\n",s,regnames[rp.r1],regnames[tp]);
+ s=longcmd(s);
+ if(!short_add){
+ p->q2.am->offset+=2;
+ emit(f,"\tmov\t%s,",regnames[tp]);emit_obj(f,&p->q2,t);emit(f,"\n");
+ emit(f,"\t%s\t%s,%s\n",s,regnames[rp.r2],regnames[tp]);
+ p->q2.am->offset-=2;
+ }
+ }else{
+ if(p->q2.am->flags==POST_INC&&p->q2.am->base<=4){
+ emit(f,"\t%s%s\t%s,",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg]);
+ emit_obj(f,&p->q2,t);emit(f,"\n");
+ }else{
+ BSET(regs_modified,tp);
+ emit(f,"\tmov%s\t%s,",x_t[t&NQ],(t&NQ)==CHAR?bregnames[tp]:regnames[tp]);
+ emit_obj(f,&p->q2,t);emit(f,"\n");
+ emit(f,"\t%s%s\t%s,%s\n",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg],(t&NQ)==CHAR?bregnames[tp]:regnames[tp]);
+ }
+ }
+ }else if((p->q2.flags&(VAR|VARADR|REG))==VAR&&ISSTATIC(p->q2.v)){
+ if(ISFAR(p->q2.v)){
+ emit(f,"\texts\t#SEG ");isseg=1;emit_obj(f,&p->q2,t);
+ emit(f,",#%d\n",(reg_pair(reg,&rp)?2:1));
+ }
+ if(reg_pair(reg,&rp)){
+ emit(f,"\t%s\t%s,",s,regnames[rp.r1]);
+ emit_obj(f,&p->q2,t);emit(f,"\n");
+ s=longcmd(s);
+ if(!short_add){
+ emit(f,"\t%s\t%s,",s,regnames[rp.r2]);
+ emit_obj(f,&p->q2,t);emit(f,"+2\n");
+ }
+ }else{
+ emit(f,"\t%s%s\t%s,",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg]);
+ emit_obj(f,&p->q2,t);emit(f,"\n");
+ }
+ }else if(isconst(q2)){
+ if(ISFLOAT(t)) ierror(0);
+ if(reg_pair(reg,&rp)){
+ long l;
+/* rfi: shift constant must be evaluated according to own type
+ eval_const(&p->q2.val,t);
+*/
+ eval_const(&p->q2.val,q2typ(p));
+ if(c==RSHIFT){
+ l=zm2l(vmax);
+/* rfi: new generation for constant right shift */
+ if( l < 0) {
+ /* TODO: we should raise a warning */
+ /* Implementation dependent: negative shift is same as null shift */
+ /* avoid shift generation */
+ } else if( l > 31) {
+ /* TODO: we should raise a warning */
+ /* Implementation dependent: same behaviour as non const shift */
+ if( t & UNSIGNED)
+ emit(f,"\tmov\t%s,#0\n",regnames[rp.r2]);
+ else
+ emit(f,"\t%s\t%s,#15\n",s,regnames[rp.r2]);
+
+ emit(f,"\tmov\t%s,%s\n",regnames[rp.r1],regnames[rp.r2]);
+ } else if( l > 15) {
+ emit(f,"\tmov\t%s,%s\n",regnames[rp.r1],regnames[rp.r2]);
+ if( t & UNSIGNED)
+ emit(f,"\tmov\t%s,#0\n",regnames[rp.r2]);
+ else
+ emit(f,"\t%s\t%s,#15\n",s,regnames[rp.r2]);
+
+ l -= 16 ;
+ if( l > 0)
+ emit(f,"\t%s\t%s,#%ld\n",s,regnames[rp.r1],l);
+ } else if( l == 0) {
+ /* avoid shift generation */
+ } else if( l == 1) {
+ emit(f,"\tshr\t%s,#1\n",regnames[rp.r1]);
+ emit(f,"\tbmov\t%s.15,%s.0\n",regnames[rp.r1],regnames[rp.r2]);
+ emit(f,"\t%s\t%s,#1\n",s,regnames[rp.r2]);
+ } else {
+/* rfi: warning should be raised in corresponding case (see TODO above)
+ if(l<1||l>15) ierror(0);
+*/
+ BSET(regs_modified,tp);
+ emit(f,"\tmov\t%s,%s\n",regnames[tp],regnames[rp.r2]);
+ emit(f,"\tshr\t%s,#%ld\n",regnames[rp.r1],l);
+ emit(f,"\t%s\t%s,#%ld\n",s,regnames[rp.r2],l);
+ emit(f,"\tshl\t%s,#%ld\n",regnames[tp],16-l);
+ emit(f,"\tor\t%s,%s\n",regnames[rp.r1],regnames[tp]);
+ }
+ }else if(c==LSHIFT){
+ l=zm2l(vmax);
+/* rfi: new generation for constant left shift */
+ if( l < 0) {
+ /* TODO: we should raise a warning */
+ /* Implementation dependent: negative shift is same as null shift */
+ /* avoid shift generation */
+ } else if( l > 31) {
+ /* TODO: we should raise a warning */
+ /* Implementation dependent: same behaviour as non const shift */
+ emit(f,"\tmov\t%s,#0\n",regnames[rp.r1]);
+ emit(f,"\tmov\t%s,%s\n",regnames[rp.r2],regnames[rp.r1]);
+ } else if( l > 15) {
+ emit(f,"\tmov\t%s,%s\n",regnames[rp.r2],regnames[rp.r1]);
+ emit(f,"\tmov\t%s,#0\n",regnames[rp.r1]);
+ l -= 16 ;
+ if( l > 0)
+ emit(f,"\tshl\t%s,#%ld\n",regnames[rp.r2],l);
+ } else if( l == 0) {
+ /* avoid shift generation */
+ } else if( l == 1) {
+ emit(f,"\tadd\t%s,%s\n",regnames[rp.r1],regnames[rp.r1]);
+ emit(f,"\taddc\t%s,%s\n",regnames[rp.r2],regnames[rp.r2]);
+ } else
+/* rfi: warning should be raised in corresponding case (see TODO above)
+ if(l<1||l>15) ierror(0);
+*/
+ if(l==2){
+ emit(f,"\tadd\t%s,%s\n",regnames[rp.r1],regnames[rp.r1]);
+ emit(f,"\taddc\t%s,%s\n",regnames[rp.r2],regnames[rp.r2]);
+ emit(f,"\tadd\t%s,%s\n",regnames[rp.r1],regnames[rp.r1]);
+ emit(f,"\taddc\t%s,%s\n",regnames[rp.r2],regnames[rp.r2]);
+ }else{
+ BSET(regs_modified,tp);
+ emit(f,"\tmov\t%s,%s\n",regnames[tp],regnames[rp.r1]);
+ emit(f,"\tshl\t%s,#%ld\n",regnames[rp.r1],l);
+ emit(f,"\tshl\t%s,#%ld\n",regnames[rp.r2],l);
+ emit(f,"\tshr\t%s,#%ld\n",regnames[tp],16-l);
+ emit(f,"\tor\t%s,%s\n",regnames[rp.r2],regnames[tp]);
+ }
+ }else{
+ l=zm2l(zmand(vmax,l2zm(65535L)));
+ emit(f,"\t%s\t%s,#%ld\n",s,regnames[rp.r1],l);
+ l=zm2l(zmrshift(vmax,l2zm(16L)));
+ s=longcmd(s);
+ if(!short_add) emit(f,"\t%s\t%s,#%ld\n",s,regnames[rp.r2],l);
+ }
+ }else{
+ emit(f,"\t%s%s\t%s,",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg]);
+ emit_obj(f,&p->q2,t);emit(f,"\n");
+ }
+ }else if(p->q2.flags&VARADR){
+ p->q2.flags&=~VARADR;
+ if(reg_pair(reg,&rp)){
+ emit(f,"\t%s\t%s,#SOF ",s,regnames[rp.r1]);emit_obj(f,&p->q2,t);emit(f,"\n");
+ s=longcmd(s);
+ if(!short_add)
+ emit(f,"\t%s\t%s,#SEG ",s,regnames[rp.r2]);isseg=1;emit_obj(f,&p->q2,t);emit(f,"\n");
+ }else{
+ emit(f,"\t%s\t%s,#",s,regnames[reg]);emit_obj(f,&p->q2,t);emit(f,"\n");
+ }
+ p->q2.flags|=VARADR;
+ }else if(p->q2.flags&DREFOBJ){
+ int seg=0,sof=0;
+ /* if(!(p->q2.flags®)) ierror(0);*/
+ if(reg_pair(p->q2.reg,&rp)){
+ seg=rp.SEG;sof=rp.SOF;
+ if(!short_add&®_pair(reg,&rp)){
+ emit(f,"\texts\t%s,#2\n",regnames[seg]);
+ }else
+ emit(f,"\texts\t%s,#1\n",regnames[seg]);
+ }
+ if(reg_pair(reg,&rp)){
+ if(scratchreg(p->q2.reg,p)){
+ emit(f,"\t%s\t%s,[%s+]\n",s,regnames[rp.r1],regnames[sof?sof:p->q2.reg]);
+ s=longcmd(s);
+ if(!short_add) emit(f,"\t%s\t%s,[%s]\n",s,regnames[rp.r2],regnames[sof?sof:p->q2.reg]);
+ }else{
+ emit(f,"\t%s\t%s,[%s]\n",s,regnames[rp.r1],regnames[sof?sof:p->q2.reg]);
+ s=longcmd(s);
+ if(!short_add){
+ BSET(regs_modified,tp);
+ emit(f,"\tmov\t%s,[%s+#2]\n",regnames[tp],regnames[sof?sof:p->q2.reg]);
+ emit(f,"\t%s\t%s,%s\n",s,regnames[rp.r2],regnames[tp]);
+ }
+ }
+ }else{
+ emit(f,"\t%s%s\t%s,",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg]);
+ emit_obj(f,&p->q2,t);emit(f,"\n");
+ }
+ }else if((p->q2.flags&(VAR|DREFOBJ))==VAR&&(p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER)){
+ long l=voff(&p->q2);
+ if(reg_pair(reg,&rp)){
+ if(l){
+ BSET(regs_modified,tp);
+ emit(f,"\tmov\t%s,[%s+#%ld]\n",regnames[tp],regnames[sp],l);
+ emit(f,"\t%s\t%s,%s\n",s,regnames[rp.r1],regnames[tp]);
+ }else
+ emit(f,"\t%s\t%s,[%s]\n",s,regnames[rp.r1],regnames[sp]);
+ s=longcmd(s);
+ if(!short_add){
+ BSET(regs_modified,tp);
+ emit(f,"\tmov\t%s,[%s+#%ld]\n",regnames[tp],regnames[sp],l+2);
+ emit(f,"\t%s\t%s,%s\n",s,regnames[rp.r2],regnames[tp]);
+ }
+ }else{
+ if(l){
+ BSET(regs_modified,tp);
+ emit(f,"\tmov%s\t%s,[%s+#%ld]\n",x_t[t&NQ],(t&NQ)==CHAR?bregnames[tp]:regnames[tp],regnames[sp],l);
+ emit(f,"\t%s%s\t%s,%s\n",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg],(t&NQ)==CHAR?bregnames[tp]:regnames[tp]);
+ }else
+ emit(f,"\t%s%s\t%s,[%s]\n",s,x_t[t&NQ],(t&NQ)==CHAR?bregnames[reg]:regnames[reg],regnames[sp]);
+ }
+ }else
+ ierror(0);
+ if(c==MULT) emit(f,"\tmov\t%s,MDL\n",regnames[reg]);
+ /*FIXME:signed*/
+ if(short_add==1) emit(f,"\t%s\t%s,#0\n",s,regnames[rp.r2]);
+ if(c!=COMPARE) save_result(f,reg,p,t);
+ if(!ISLWORD(t)||((c==ADD||c==SUB||c==ADDI2P||c==SUBIFP)&&!short_add)){
+ cc=&p->z;cc_t=t;
+ }else
+ cc=0;
+ continue;
+ }
+ ierror(0);
+ }
+ if(notpopped){
+ emit(f,"\tadd\t%s,#%ld\n",regnames[sp],notpopped);
+ pop(notpopped,0);notpopped=0;
+ }
+ function_bottom(f,v,loff);
+}
+
+int shortcut(int c,int t)
+{
+ if(c==COMPARE||c==AND||c==OR||c==XOR) return 1;
+ if((t&NQ)!=BIT&&(c==ADD||c==SUB)) return 1;
+ return 0;
+}
+
+void cleanup_cg(FILE *f)
+{
+ struct fpconstlist *p;
+ unsigned char *ip;
+ if(f&&stack_check){
+ emit(f,"\t%s\t%s__stack_check\n",public,idprefix);
+ }
+ while(p=firstfpc){
+ if(f){
+ new_section(f,NDATA);
+ emit(f,even);
+ emit(f,"%s%d:\n\t%s\t",labprefix,p->label,TASKING?dct[SHORT]:vdct[SHORT]);
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+ if((p->typ&NQ)==DOUBLE||(p->typ&NQ)==LDOUBLE){
+ emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+ }
+ emit(f,"\n");
+ }
+ firstfpc=p->next;
+ free(p);
+ }
+ if(f&&TASKING) emit(f,"%s\tREGDEF R0-R15\n\tend\n",sec_end);
+}
+
+int reg_parm(struct reg_handle *p,struct Typ *t,int mode,struct Typ *fkt)
+{
+ int f=t->flags&NQ;
+ if(!ISSCALAR(f)) return 0;
+ if(p->gpr>3||mode) return 0;
+ if(f==LLONG||f==DOUBLE||f==LDOUBLE)
+ return 0;
+ else if(f==LONG||f==FPOINTER||f==HPOINTER){
+ if(p->gpr==0) {p->gpr=2;return 23;}
+ if(p->gpr==1) {p->gpr=3;return 22;}
+ if(p->gpr==2) {p->gpr=4;return 21;}
+ return 0;
+ }else
+ return 13+p->gpr++;
+}
+
+void insert_const(union atyps *p,int t)
+/* Traegt Konstante in entprechendes Feld ein. */
+{
+ if(!p) ierror(0);
+/* *p = (union atyps) 0 ; /* rfi: clear unused bits */
+ t&=NU;
+ if(t==BIT) {if(zmeqto(zc2zm(vchar),l2zm(0L))) p->vchar=zm2zc(l2zm(0L)); else p->vchar=zm2zc(l2zm(1L));return;}
+ if(t==CHAR) {p->vchar=vchar;return;}
+ if(t==SHORT) {p->vshort=vshort;return;}
+ if(t==INT) {p->vint=vint;return;}
+ if(t==LONG) {p->vlong=vlong;return;}
+ if(t==LLONG) {p->vllong=vllong;return;}
+ if(t==MAXINT) {p->vmax=vmax;return;}
+ if(t==(UNSIGNED|BIT)) {if(zumeqto(zuc2zum(vuchar),ul2zum(0UL))) p->vuchar=zum2zuc(ul2zum(0UL)); else p->vuchar=zum2zuc(ul2zum(1UL));return;}
+ if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+ if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+ if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+ if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+ if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+ if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+ if(t==FLOAT) {p->vfloat=vfloat;return;}
+ if(t==DOUBLE) {p->vdouble=vdouble;return;}
+ if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+ if(t==NPOINTER) {p->vuint=vuint;return;}
+ if(t==FPOINTER||t==HPOINTER) {p->vulong=vulong;return;}
+}
+void eval_const(union atyps *p,int t)
+/* Weist bestimmten globalen Variablen Wert einer CEXPR zu. */
+{
+ int f=t&NQ;
+ if(!p) ierror(0);
+ if(f==MAXINT||(f>=BIT&&f<=LLONG)){
+ if(!(t&UNSIGNED)){
+ if(f==BIT){
+ if(zmeqto(zc2zm(p->vchar),l2zm(0L))) vmax=l2zm(0L); else vmax=l2zm(1L);
+ }else if(f==CHAR) vmax=zc2zm(p->vchar);
+ else if(f==SHORT)vmax=zs2zm(p->vshort);
+ else if(f==INT) vmax=zi2zm(p->vint);
+ else if(f==LONG) vmax=zl2zm(p->vlong);
+ else if(f==LLONG) vmax=zll2zm(p->vllong);
+ else if(f==MAXINT) vmax=p->vmax;
+ else ierror(0);
+ vumax=zm2zum(vmax);
+ vldouble=zm2zld(vmax);
+ }else{
+ if(f==BIT){
+ if(zumeqto(zuc2zum(p->vuchar),ul2zum(0UL))) vumax=ul2zum(0UL); else vumax=ul2zum(1UL);
+ }else if(f==CHAR) vumax=zuc2zum(p->vuchar);
+ else if(f==SHORT)vumax=zus2zum(p->vushort);
+ else if(f==INT) vumax=zui2zum(p->vuint);
+ else if(f==LONG) vumax=zul2zum(p->vulong);
+ else if(f==LLONG) vumax=zull2zum(p->vullong);
+ else if(f==MAXINT) vumax=p->vumax;
+ else ierror(0);
+ vmax=zum2zm(vumax);
+ vldouble=zum2zld(vumax);
+ }
+ }else{
+ if(ISPOINTER(f)){
+ if(f==NPOINTER)
+ vumax=zui2zum(p->vuint);
+ else
+ vumax=zul2zum(p->vulong);
+ vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+ }else{
+ if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+ else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+ else vldouble=p->vldouble;
+ vmax=zld2zm(vldouble);
+ vumax=zld2zum(vldouble);
+ }
+ }
+ vfloat=zld2zf(vldouble);
+ vdouble=zld2zd(vldouble);
+ vuchar=zum2zuc(vumax);
+ vushort=zum2zus(vumax);
+ vuint=zum2zui(vumax);
+ vulong=zum2zul(vumax);
+ vullong=zum2zull(vumax);
+ vchar=zm2zc(vmax);
+ vshort=zm2zs(vmax);
+ vint=zm2zi(vmax);
+ vlong=zm2zl(vmax);
+ vllong=zm2zll(vmax);
+}
+void printval(FILE *f,union atyps *p,int t)
+/* Gibt atyps aus. */
+{
+ t&=NU;
+ if(t==BIT){fprintf(f,"B");vmax=zc2zm(p->vchar);fprintf(f,"%d",!zmeqto(vmax,l2zm(0L)));}
+ if(t==(UNSIGNED|BIT)){fprintf(f,"UB");vumax=zuc2zum(p->vuchar);fprintf(f,"%d",!zumeqto(vmax,ul2zum(0UL)));}
+ if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+ if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+ if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+ if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+ if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+ if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+ if(t==(UNSIGNED|INT)||t==NPOINTER){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+ if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+ if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+ if(t==MAXINT) printzm(f,p->vmax);
+ if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax);
+}
+void emitval(FILE *f,union atyps *p,int t)
+/* Gibt atyps aus. */
+{
+ t&=NU;
+ if(t==BIT){vmax=zc2zm(p->vchar);emit(f,"%d",!zmeqto(vmax,l2zm(0L)));}
+ if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);emit(f,"%d",!zumeqto(vumax,ul2zum(0UL)));}
+ if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+ if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+ if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+ if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+ if(t==LDOUBLE){emitzld(f,p->vldouble);}
+ if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+ if(t==(UNSIGNED|INT)||t==NPOINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+ if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+ if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+ if(t==MAXINT) emitzm(f,p->vmax);
+ if(t==(UNSIGNED|MAXINT)) emitzum(f,p->vumax);
+}
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+ char *attr;
+ while(p){
+ if(ISPOINTER(p->flags)){
+ p->flags=((p->flags&~NU)|POINTER_TYPE(p->next));
+ if(attr=p->next->attr){
+ if(strstr(attr,STR_NEAR))
+ p->flags=((p->flags&~NU)|NPOINTER);
+ if(strstr(attr,STR_FAR))
+ p->flags=((p->flags&~NU)|FPOINTER);
+ if(strstr(attr,STR_HUGE))
+ p->flags=((p->flags&~NU)|HPOINTER);
+ }
+ }
+ if(ISINT(p->flags)&&(attr=p->attr)&&strstr(attr,"bit"))
+ p->flags=((p->flags&~NU)|BIT);
+ p=p->next;
+ }
+}
+
+void init_db(FILE *f)
+{
+}
+
+void cleanup_db(FILE *f)
+{
+}
+
+char *use_libcall(int c,int t,int t2)
+{
+ static char fname[16];
+ char *ret=0,*tt;
+
+ if(c==COMPARE){
+ if((t&NQ)==LLONG||ISFLOAT(t)){
+ sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }else{
+ t&=NU;
+ t2&=NU;
+ if(t==LDOUBLE) t=DOUBLE;
+ if(t2==LDOUBLE) t2=DOUBLE;
+ if(c==CONVERT){
+ if(t==t2) return 0;
+ if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+ if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+
+ if(ISFLOAT(t)){
+ sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64);
+ ret=fname;
+ }
+ if(ISFLOAT(t2)&&(t&NU)==LLONG){
+ sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+ if((t&NQ)==LLONG||ISFLOAT(t)){
+ if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+ if(t==(UNSIGNED|LLONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint64",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==LLONG){
+ sprintf(fname,"__%sint64",ename[c]);
+ ret=fname;
+ }else{
+ sprintf(fname,"__%s%s%s%ld",ename[c],(t&UNSIGNED)?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+ }
+ }
+
+
+ return ret;
+}
diff --git a/machines/c16x/machine.dt b/machines/c16x/machine.dt
new file mode 100755
index 0000000..eab38c9
--- /dev/null
+++ b/machines/c16x/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S16BULE S16BUBE
+
+
diff --git a/machines/c16x/machine.h b/machines/c16x/machine.h
new file mode 100755
index 0000000..be6dbdd
--- /dev/null
+++ b/machines/c16x/machine.h
@@ -0,0 +1,184 @@
+/* Example of a code-generator for SAB c16x 16bit microcontrollers.*/
+
+#include "dt.h"
+
+/* We have extended types! What we have to do to support them: */
+/* - #define HAVE_EXT_TYPES
+ - #undef all standard types
+ - #define all standard types plus new types
+ - write eval_const and insert_const
+ - write typedefs for zmax and zumax
+ - write typname[]
+ - write conv_typ()
+ - optionally #define ISPOINTER, ISARITH, ISINT etc.
+ - optionally #define HAVE_TGT_PRINTVAL and write printval
+ - optionally #define POINTER_TYPE
+ - optionally #define HAVE_TGT_FALIGN and write falign
+ - optionally #define HAVE_TGT_SZOF and write szof
+ - optionally add functions for attribute-handling
+*/
+#define HAVE_EXT_TYPES 1
+
+#define HAVE_TGT_PRINTVAL
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef BOOL
+#undef MAXINT
+#undef MAX_TYPE
+
+#define BIT 1
+#define CHAR 2
+#define SHORT 3
+#define INT 4
+#define LONG 5
+#define LLONG 6
+#define FLOAT 7
+#define DOUBLE 8
+#define LDOUBLE 9
+#define VOID 10
+#define NPOINTER 11
+#define FPOINTER 12
+#define HPOINTER 13
+#define ARRAY 14
+#define STRUCT 15
+#define UNION 16
+#define ENUM 17
+#define FUNKT 18
+#define BOOL 19
+
+#define MAXINT 20
+
+#define MAX_TYPE MAXINT
+
+#define POINTER_TYPE(x) pointer_type(x)
+extern int pointer_type();
+#define ISPOINTER(x) ((x&NQ)>=NPOINTER&&(x&NQ)<=HPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=BIT&&(x&NQ)<=HPOINTER)
+#define ISINT(x) ((x&NQ)>=BIT&&(x&NQ)<=LLONG)
+#define PTRDIFF_T(x) ((x)==HPOINTER?LONG:INT)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+ zchar vchar;
+ zuchar vuchar;
+ zshort vshort;
+ zushort vushort;
+ zint vint;
+ zuint vuint;
+ zlong vlong;
+ zulong vulong;
+ zllong vllong;
+ zullong vullong;
+ zmax vmax;
+ zumax vumax;
+ zfloat vfloat;
+ zdouble vdouble;
+ zldouble vldouble;
+};
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Not used in this code-generrator. */
+struct AddressingMode{
+ int flags;
+ int base;
+ long offset;
+ struct Var *v;
+};
+
+/* This type will be added to every IC. Can be used by the cg. */
+#define HAVE_EXT_IC 1
+struct ext_ic {
+ int flags;
+ int r;
+ long offset;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR 25
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 10
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P INT
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 0
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 1
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+#define HAVE_REGPARMS 1
+
+struct reg_handle {
+ int gpr;
+};
+
+/* We use unsigned int as size_t rather than unsigned long which */
+/* is the default setting. */
+#define HAVE_INT_SIZET 1
+
+/* We have register pairs. */
+#define HAVE_REGPAIRS 1
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+#define HAVE_TARGET_RALLOC 1
+#define cost_load_reg(r,v) 4
+#define cost_save_reg(r,v) 4
+#define cost_move_reg(i,j) 2
+#define cost_pushpop_reg(r) 2
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/* We have asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES 1
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
diff --git a/machines/dv/machine.c b/machines/dv/machine.c
new file mode 100755
index 0000000..264d677
--- /dev/null
+++ b/machines/dv/machine.c
@@ -0,0 +1,1112 @@
+/*
+ Dalvik backend for vbcc
+*/
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc dalvik code-generator V0.1 (c) in 2012 by Volker Barthelmann";
+
+/* Commandline-flags the code-generator accepts:
+ 0: just a flag
+ VALFLAG: a value must be specified
+ STRINGFLAG: a string can be specified
+ FUNCFLAG: a function will be called
+ apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]={0,0,
+ VALFLAG,VALFLAG,VALFLAG,
+ 0,0,
+ VALFLAG,VALFLAG,0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+ they collide with the frontend */
+char *g_flags_name[MAXGF]={"three-addr","load-store",
+ "volatile-gprs","volatile-fprs","volatile-ccrs",
+ "imm-ind","gpr-ind",
+ "gpr-args","fpr-args","use-commons"};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. will be initialized in init_cg(),
+ register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+ estimated cost-saving can be obtained by several registers, the
+ one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__interrupt",0};
+
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+#define THREE_ADDR (g_flags[0]&USEDFLAG)
+#define LOAD_STORE (g_flags[1]&USEDFLAG)
+#define VOL_GPRS ((g_flags[2]&USEDFLAG)?g_flags_val[2].l:NUM_GPRS/2)
+#define VOL_FPRS ((g_flags[3]&USEDFLAG)?g_flags_val[3].l:NUM_FPRS/2)
+#define VOL_CCRS ((g_flags[4]&USEDFLAG)?g_flags_val[4].l:NUM_CCRS/2)
+#define IMM_IND ((g_flags[5]&USEDFLAG)?1:0)
+#define GPR_IND ((g_flags[6]&USEDFLAG)?2:0)
+#define GPR_ARGS ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:0)
+#define FPR_ARGS ((g_flags[8]&USEDFLAG)?g_flags_val[8].l:0)
+#define USE_COMMONS (g_flags[9]&USEDFLAG)
+
+
+#ifdef DV_BYTE8
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]= {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,4,4,8,4,8,8,0,8,0,0,0,4,0};
+#else
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]= {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,1,1,1,2,1,2,2,0,2,0,0,0,1,0};
+#endif
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp={LONG},ldbl={DOUBLE},lchar={CHAR};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+ "__GENERIC__",
+ 0};
+
+/* special registers */
+static int sp; /* Stackpointer */
+static int t1,t2,t3; /* temporary gprs */
+static int f1,f2,f3; /* temporary fprs */
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\t.text\n",
+ *dataname="\t.data\n",
+ *bssname="",
+ *rodataname="\t.section\t.rodata\n";
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix=":",*idprefix="";
+
+#if FIXED_SP
+/* variables to calculate the size and partitioning of the stack-frame
+ in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+#else
+/* variables to keep track of the current stack-offset in the case of
+ a moving stack-pointer */
+static long notpopped,dontpop,stackoffset,maxpushed;
+#endif
+
+static long localsize,rsavesize,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+static long real_offset(struct obj *o)
+{
+ long off=zm2l(o->v->offset);
+ if(off<0){
+ /* function parameter */
+ ierror(0);
+ }
+
+ off+=zm2l(o->val.vmax);
+ return off;
+}
+
+/* Initializes an addressing-mode structure and returns a pointer to
+ that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ am.offset=offset;
+ return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+ char *sec;
+ if(!v->vattr) return 0;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return 0;
+ sec+=strlen("section(");
+ emit(f,"\t.section\t");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/* Generates code to load the address of a variable into register r. */
+{
+ if(!(o->flags&VAR)) ierror(0);
+ if(!reg_pair(r,&rp)) ierror(0);
+
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+ long off=real_offset(o);
+ emit(f,"\tmove-int\t%s,%s\n",mregnames[rp.r2],mregnames[fp]);
+ emit(f,"\tconst-int\t%s,%ld\n",mregnames[rp.r1],loff);
+ }else{
+ emit(f,"\tconst-int\t%s,%s\n",mregnames[rp.r2],gp);
+ emit(f,"\tconst-int\t%s,",mregnames[rp.r1]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }
+}
+/* Generates code to load a memory object into register r. tmp is a
+ general purpose register which may be used. tmp can be r. */
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+ type&=NU;
+ if(o->flags&VARADR){
+ load_address(f,r,o,POINTER);
+ }else{
+ if((o->flags&(REG|DREFOBJ))==REG&&o->reg==r)
+ return;
+#ifdef DV_BYTE8
+ ierror(0);
+#else
+ ierror(0);
+#endif
+ }
+}
+
+/* Generates code to store register r into memory object o. */
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+ type&=NQ;
+ emit(f,"\tmov.%s\t",dt(type));
+ emit_obj(f,o,type);
+ emit(f,",%s\n",regnames[r]);
+}
+
+/* Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+
+static struct IC *preload(FILE *,struct IC *);
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
+
+/* Does some pre-processing like fetching operands from memory to
+ registers etc. */
+static struct IC *preload(FILE *f,struct IC *p)
+{
+ int r;
+
+ if(isreg(q1))
+ q1reg=p->q1.reg;
+ else
+ q1reg=0;
+
+ if(isreg(q2))
+ q2reg=p->q2.reg;
+ else
+ q2reg=0;
+
+ if(isreg(z)){
+ zreg=p->z.reg;
+ }else{
+ if(ISFLOAT(ztyp(p)))
+ zreg=f1;
+ else
+ zreg=t1;
+ }
+
+ if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am){
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,t1,&p->q1,q1typ(p));
+ p->q1.reg=t1;
+ p->q1.flags|=(REG|DREFOBJ);
+ }
+ if(p->q1.flags&&LOAD_STORE&&!isreg(q1)){
+ if(ISFLOAT(q1typ(p)))
+ q1reg=f1;
+ else
+ q1reg=t1;
+ load_reg(f,q1reg,&p->q1,q1typ(p));
+ p->q1.reg=q1reg;
+ p->q1.flags=REG;
+ }
+
+ if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am){
+ p->q2.flags&=~DREFOBJ;
+ load_reg(f,t1,&p->q2,q2typ(p));
+ p->q2.reg=t1;
+ p->q2.flags|=(REG|DREFOBJ);
+ }
+ if(p->q2.flags&&LOAD_STORE&&!isreg(q2)){
+ if(ISFLOAT(q2typ(p)))
+ q2reg=f2;
+ else
+ q2reg=t2;
+ load_reg(f,q2reg,&p->q2,q2typ(p));
+ p->q2.reg=q2reg;
+ p->q2.flags=REG;
+ }
+ return p;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+ if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
+ p->z.flags&=~DREFOBJ;
+ load_reg(f,t2,&p->z,POINTER);
+ p->z.reg=t2;
+ p->z.flags|=(REG|DREFOBJ);
+ }
+ if(isreg(z)){
+ if(p->z.reg!=zreg)
+ emit(f,"\tmov.%s\t%s,%s\n",dt(ztyp(p)),regnames[p->z.reg],regnames[zreg]);
+ }else{
+ store_reg(f,zreg,&p->z,ztyp(p));
+ }
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+ if(p->am){
+ ierror(0);
+ }
+ if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if(p->flags&DREFOBJ) ierror(0);
+ if(p->flags®){
+ emit(f,"%s",regnames[p->reg]);
+ }else if(p->flags&VAR) {
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+ ierror(0);
+ emit(f,"%ld(%s)",real_offset(p),regnames[sp]);
+ else{
+ if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ }
+ }
+ if(p->flags&KONST){
+ emitval(f,&p->val,t&NU);
+ }
+ /*if(p->flags&DREFOBJ) emit(f,")");*/
+}
+
+/* Test if there is a sequence of FREEREGs containing FREEREG reg.
+ Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+ while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+ if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+ p=p->next;
+ }
+ return 0;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+ int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+ return;
+
+ for(;p;p=p->next){
+ c=p->code;
+ if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+ if(c==LABEL) exit_label=p->typf;
+
+ /* Try const(reg) */
+ if(IMM_IND&&(c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+ int base;zmax of;struct obj *o;
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ if(1/*zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))*/){
+ r=p->z.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ am->base=base;
+ am->offset=zm2l(of);
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+ /* Try reg,reg */
+ if(GPR_IND&&c==ADDI2P&&isreg(q2)&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+ int base,idx;struct obj *o;
+ r=p->z.reg;idx=p->q2.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||(q1typ(p2)&NQ)==LLONG) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||(q2typ(p2)&NQ)==LLONG) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||(ztyp(p2)&NQ)==LLONG) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=GPR_IND;
+ am->base=base;
+ am->offset=idx;
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+ rsavesize=0;
+ if(!special_section(f,v)&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+}
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+ emit(f,ret);
+}
+
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+int init_cg(void)
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(8L);
+ char_bit=l2zm(8L);
+ stackalign=l2zm(4);
+
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+
+ regnames[0]="noreg";
+ for(i=1;i<=GPRS;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"v%d",i-1);
+#ifdef DV_BYTE8
+ regsize[i]=l2zm(4L);
+#else
+ regsize[i]=l2zm(1L);
+#endif
+ regtype[i]=<yp;
+ }
+ for(i=GPRS+1;i<=GPRS+PAIRS+1;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"v%d/v%d",i-GPRS-1,i-GPRS);
+#ifdef DV_BYTE8
+ regsize[i]=l2zm(8L);
+#else
+ regsize[i]=l2zm(2L);
+#endif
+ regtype[i]=&llong;
+ }
+
+ /* Use multiple ccs. */
+ multiple_ccs=0;
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+#ifdef DV_BYTE8
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+#else
+ t_min[CHAR]=t_min[SHORT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_max[CHAR]=t_max[SHORT]=ul2zum(2147483647UL);
+ tu_max[CHAR]=tu_max[SHORT]=ul2zum(4294967295UL);
+#endif
+ t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LONG]=t_min(INT);
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=ul2zum(2147483647UL);
+ t_max[LONG]=t_max(INT);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[INT]=ul2zum(4294967295UL);
+ tu_max[LONG]=t_max(UNSIGNED|INT);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ /* This is not optimal but simple. */
+ sp=FIRST_GPR;
+ t1=FIRST_GPR+1;
+ t2=FIRST_GPR+2;
+ f1=FIRST_FPR;
+ f2=FIRST_FPR+1;
+ regsa[t1]=regsa[t2]=1;
+ regsa[f1]=regsa[f2]=1;
+ regsa[sp]=1;
+ regscratch[t1]=regscratch[t2]=0;
+ regscratch[f1]=regscratch[f2]=0;
+ regscratch[sp]=0;
+
+ for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++)
+ regscratch[i]=1;
+ for(i=FIRST_FPR;i<=LAST_FPR-VOL_FPRS;i++)
+ regscratch[i]=1;
+ for(i=FIRST_CCR;i<=LAST_CCR-VOL_CCRS;i++)
+ regscratch[i]=1;
+
+ target_macros=marray;
+
+
+ return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+/* A pointer MUST be returned in a register. The code-generator */
+/* has to simulate a pseudo register if necessary. */
+{
+ if(ISFLOAT(t->flags))
+ return FIRST_FPR+2;
+ if(ISSTRUCT(t->flags)||ISUNION(t->flags))
+ return 0;
+ if(zmleq(szof(t),l2zm(4L)))
+ return FIRST_GPR+3;
+ else
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+ register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+ int c=p->code;
+ if(o->flags&VKONST){
+ if(!LOAD_STORE)
+ return 0;
+ if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
+ return 4;
+ else
+ return 2;
+ }
+ if(o->flags&DREFOBJ)
+ return 4;
+ if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+ if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+ return 2;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(r==0)
+ return 0;
+ t&=NQ;
+ if(t==0&&r>=FIRST_CCR&&r<=LAST_CCR)
+ return 1;
+ if(ISFLOAT(t)&&r>=FIRST_FPR&&r<=LAST_FPR)
+ return 1;
+ if(t==POINTER&&r>=FIRST_GPR&&r<=LAST_GPR)
+ return 1;
+ if(t>=CHAR&&t<=LONG&&r>=FIRST_GPR&&r<=LAST_GPR)
+ return 1;
+ return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* On the PowerPC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op=o&NQ,tp=t&NQ;
+ if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
+ return 0;
+ if(op==DOUBLE&&tp==LDOUBLE) return 0;
+ if(op==LDOUBLE&&tp==DOUBLE) return 0;
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ if(newobj&§ion!=SPECIAL)
+ emit(f,"%ld\n",zm2l(size));
+ else
+ emit(f,"\t.space\t%ld\n",zm2l(size));
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ if(zm2l(align)>1) emit(f,"\t.align\t2\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;char *sec;
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(v->clist||section==SPECIAL){
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }else
+ emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+ newobj=1;
+ }
+ if(v->storage_class==EXTERN){
+ emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+ if(v->flags&(DEFINED|TENTATIVE)){
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(v->clist||section==SPECIAL){
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ emit(f,"\tdc.%s\t",dt(t&NQ));
+ if(!p->tree){
+ if(ISFLOAT(t)){
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ if((t&NQ)!=FLOAT){
+ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ }else{
+ emitval(f,&p->val,t&NU);
+ }
+ }else{
+ emit_obj(f,&p->tree->o,t&NU);
+ }
+ emit(f,"\n");newobj=0;
+}
+
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/* The main code-generation. */
+{
+ int c,t,i;
+ struct IC *m;
+ argsize=0;
+ if(DEBUG&1) printf("gen_code()\n");
+ for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+ maxpushed=0;
+
+ /*FIXME*/
+ ret="\trts\n";
+
+ for(m=p;m;m=m->next){
+ c=m->code;t=m->typf&NU;
+ if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
+ if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
+
+ /* convert MULT/DIV/MOD with powers of two */
+ if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+ eval_const(&m->q2.val,t);
+ i=pof2(vmax);
+ if(i){
+ if(c==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ m->code=AND;
+ }else{
+ vmax=l2zm(i-1);
+ if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+ }
+ c=m->code;
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ if(c==AND){
+ insert_const(&m->q2.val,t);
+ }else{
+ insert_const(&m->q2.val,INT);
+ p->typf2=INT;
+ }
+ }
+ }
+#if FIXED_SP
+ if(c==CALL&&argsize<zm2l(m->q2.val.vmax)) argsize=zm2l(m->q2.val.vmax);
+#endif
+ }
+ peephole(p);
+
+ for(c=1;c<=MAXR;c++){
+ if(regsa[c]||regused[c]){
+ BSET(regs_modified,c);
+ }
+ }
+
+ localsize=(zm2l(offset)+3)/4*4;
+#if FIXED_SP
+ /*FIXME: adjust localsize to get an aligned stack-frame */
+#endif
+
+ function_top(f,v,localsize);
+
+#if FIXED_SP
+ pushed=0;
+#endif
+
+ for(;p;p=p->next){
+ c=p->code;t=p->typf;
+ if(c==NOP) {p->z.flags=0;continue;}
+ if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
+ if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
+ if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);continue;}
+ if(c==BRA){
+ if(0/*t==exit_label&&framesize==0*/)
+ emit(f,ret);
+ else
+ emit(f,"\tb\t%s%d\n",labprefix,t);
+ continue;
+ }
+ if(c>=BEQ&&c<BRA){
+ emit(f,"\tb%s\t",ccs[c-BEQ]);
+ if(isreg(q1)){
+ emit_obj(f,&p->q1,0);
+ emit(f,",");
+ }
+ emit(f,"%s%d\n",labprefix,t);
+ continue;
+ }
+ if(c==MOVETOREG){
+ load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+ continue;
+ }
+ if(c==MOVEFROMREG){
+ store_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+ continue;
+ }
+ if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+ ierror(0);
+ }
+ p=preload(f,p);
+ c=p->code;
+ if(c==SUBPFP) c=SUB;
+ if(c==ADDI2P) c=ADD;
+ if(c==SUBIFP) c=SUB;
+ if(c==CONVERT){
+ if(ISFLOAT(q1typ(p))||ISFLOAT(ztyp(p))) ierror(0);
+ if(sizetab[q1typ(p)&NQ]<sizetab[ztyp(p)&NQ]){
+ if(q1typ(p)&UNSIGNED)
+ emit(f,"\tzext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+ else
+ emit(f,"\tsext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+ }
+ save_result(f,p);
+ continue;
+ }
+ if(c==KOMPLEMENT){
+ load_reg(f,zreg,&p->q1,t);
+ emit(f,"\tcpl.%s\t%s\n",dt(t),regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c==SETRETURN){
+ load_reg(f,p->z.reg,&p->q1,t);
+ BSET(regs_modified,p->z.reg);
+ continue;
+ }
+ if(c==GETRETURN){
+ if(p->q1.reg){
+ zreg=p->q1.reg;
+ save_result(f,p);
+ }else
+ p->z.flags=0;
+ continue;
+ }
+ if(c==CALL){
+ int reg;
+ /*FIXME*/
+#if 0
+ if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+ if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+ stack=framesize+zum2ul(p->q1.v->fi->stack1);
+ }else
+ stack_valid=0;
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ }else{
+ emit(f,"\tcall\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ /*FIXME*/
+#if FIXED_SP
+ pushed-=zm2l(p->q2.val.vmax);
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+ bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+ }else{
+ int i;
+ for(i=1;i<=MAXR;i++){
+ if(regscratch[i]) BSET(regs_modified,i);
+ }
+ }
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(t==0) ierror(0);
+ if(c==PUSH){
+#if FIXED_SP
+ emit(f,"\tmov.%s\t%ld(%s),",dt(t),pushed,regnames[sp]);
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ pushed+=zm2l(p->q2.val.vmax);
+#else
+ emit(f,"\tpush.%s\t",dt(t));
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ push(zm2l(p->q2.val.vmax));
+#endif
+ continue;
+ }
+ if(c==ASSIGN){
+ load_reg(f,zreg,&p->q1,t);
+ save_result(f,p);
+ }
+ continue;
+ }
+ if(c==ADDRESS){
+ load_address(f,zreg,&p->q1,POINTER);
+ save_result(f,p);
+ continue;
+ }
+ if(c==MINUS){
+ load_reg(f,zreg,&p->q1,t);
+ emit(f,"\tneg.%s\t%s\n",dt(t),regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c==TEST){
+ emit(f,"\ttst.%s\t",dt(t));
+ if(multiple_ccs)
+ emit(f,"%s,",regnames[zreg]);
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ if(multiple_ccs)
+ save_result(f,p);
+ continue;
+ }
+ if(c==COMPARE){
+ emit(f,"\tcmp.%s\t",dt(t));
+ if(multiple_ccs)
+ emit(f,"%s,",regnames[zreg]);
+ emit_obj(f,&p->q1,t);
+ emit(f,",");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ if(multiple_ccs)
+ save_result(f,p);
+ continue;
+ }
+ if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)){
+ if(!THREE_ADDR)
+ load_reg(f,zreg,&p->q1,t);
+ if(c>=OR&&c<=AND)
+ emit(f,"\t%s.%s\t%s,",logicals[c-OR],dt(t),regnames[zreg]);
+ else
+ emit(f,"\t%s.%s\t%s,",arithmetics[c-LSHIFT],dt(t),regnames[zreg]);
+ if(THREE_ADDR){
+ emit_obj(f,&p->q1,t);
+ emit(f,",");
+ }
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ save_result(f,p);
+ continue;
+ }
+ pric2(stdout,p);
+ ierror(0);
+ }
+ function_bottom(f,v,localsize);
+ if(stack_valid){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=stack;
+ }
+ emit(f,"# stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int code,int typ)
+{
+ return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+ int f;
+ f=t->flags&NQ;
+ if(f<=LONG||f==POINTER){
+ if(m->gregs>=GPR_ARGS)
+ return 0;
+ else
+ return FIRST_GPR+3+m->gregs++;
+ }
+ if(ISFLOAT(f)){
+ if(m->fregs>=FPR_ARGS)
+ return 0;
+ else
+ return FIRST_FPR+2+m->fregs++;
+ }
+ return 0;
+}
+
+int handle_pragma(const char *s)
+{
+}
+void cleanup_cg(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+ if(f) section=-1;
+}
+
diff --git a/machines/dv/machine.dt b/machines/dv/machine.dt
new file mode 100755
index 0000000..fa79dba
--- /dev/null
+++ b/machines/dv/machine.dt
@@ -0,0 +1,16 @@
+S32BSLE
+S32BULE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S64BULE S64BUBE
+
+
diff --git a/machines/dv/machine.h b/machines/dv/machine.h
new file mode 100755
index 0000000..cc49371
--- /dev/null
+++ b/machines/dv/machine.h
@@ -0,0 +1,127 @@
+/*
+ Dalvik backend for vbcc
+*/
+
+#include "dt.h"
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Currently possible are (const,gpr) and (gpr,gpr) */
+struct AddressingMode{
+ int flags;
+ int base;
+ long offset;
+};
+
+/* The number of registers of the target machine. */
+#define GPRS 256
+#define PAIRS (GPRS/2)
+#define MAXR (GPRS + PAIRS)
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 20
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#ifndef DV_BYTE8
+#define MINADDI2P CHAR
+#else
+#define MINADDI2P INT
+#endif
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 0
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 1
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+/* Parameters are sometimes passed in registers without __reg. */
+#define HAVE_REGPARMS 1
+
+/* Parameters on the stack should be pushed in order rather than */
+/* in reverse order. */
+#define ORDERED_PUSH FIXED_SP
+
+/* Structure for reg_parm(). */
+struct reg_handle{
+ unsigned long regs;
+};
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt
+ register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output, this can be used to do
+ peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/* We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+ optimizations on code which can already be implemented by efficient
+ assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+ etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#undef HAVE_INT_SIZET
+
+/* we need register-pairs */
+##define HAVE_REGPAIRS
+
+
+/* do not create CONVERT ICs from integers smaller than int to floats */
+#define MIN_INT_TO_FLOAT_TYPE INT
+
+/* do not create CONVERT ICs from floats to ints smaller than int */
+#define MIN_FLOAT_TO_INT_TYPE INT
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 1
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 1
diff --git a/machines/falco16/machine.c b/machines/falco16/machine.c
new file mode 100755
index 0000000..91ada14
--- /dev/null
+++ b/machines/falco16/machine.c
@@ -0,0 +1,2470 @@
+/*
+ FALCO16 v3
+*/
+
+/* TO DO
+
+- If a FREEREG follows an IC for Q1, the register can be used as temporary.
+e.g if we get a = R0 + c, and there's a FREEREG R0 following the IC, we can generate
+add r0, [c]
+mov [a], r0
+instead of
+mov r1, r0
+add r1, [c]
+mov [a], r1
+
+-- floating point capability must also be implemented
+
+- data alignement doesn't work, g1 should be aligned below.
+-- Is this supposed to be handled by the assembler?
+char global = 4;
+int g1 = 5;
+
+-- conditional branching for LONG works, but temporary register handling is not ideal.
+ Register are loaded more than required.
+
+-- inline optimization must be done, e.g shift by const, mul/div by 2
+
+-- call ptr not implemented.
+
+-- register parameter passing
+
+-- 1arg operation are currently only using reg arguments
+
+-- could take advantage of [reg+ofs] addressing mode by combining IC
+
+-- IRQs should only save registers which are actually used, in case of function call all regs must be saved
+-- implement "naked" keyword for RTOS use.
+
+-- right now lib_mov is done by messing with the IC operands changing them into pointers. It is probably better to
+ use ptr_push instead of messign around with val_push.
+
+-- must update arg_push to support double, long long and such, not using more temperary registers
+
+-- compare with KONST not correct when KONST = maxint
+
+*/
+
+#include "supp.h"
+#include "vbc.h"
+
+//static char FILE_[]=__FILE__;
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="falco16_v3 code generator v0.1 by Daniel Schoch";
+
+// command line
+//--------------
+/* Commandline-flags the code-generator accepts:
+ 0: just a flag
+ VALFLAG: a value must be specified
+ STRINGFLAG: a string can be specified
+ FUNCFLAG: a function will be called
+ apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF] = {VALFLAG, VALFLAG, VALFLAG};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+ they collide with the frontend */
+char *g_flags_name[MAXGF]={"regs", "rsave", "rtmp"};
+/* Description of command line options:
+regs=<val>
+DEFAULT = 6
+Specify the number of registers to use. Must be >=3 and <= 14.
+The value should match the actual CPU implementation, the default is 6.
+Values < 6 don't make much practical sense since there won't be
+enough registers available for efficient code generation.
+
+rsave=<val>
+DEFAULT = automatic
+0 <= val <= regs-rtmp
+Specify the number of non-scratch registers to use.
+Non-scratch registers are registers that are saved across
+function calls. They are used for efficient register
+variable implementation.
+
+rtmp=<val>
+DEFAULT = 0
+0 <= val <= 3
+Specify the number of temporary registers to reserve.
+Temporary registers are used by the code generator.
+In situation where there is no free register is available
+a register must be saved and restored.
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+
+
+// data types
+//======================
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[MAX_TYPE+1];
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+// registers
+//==========================
+
+/* Names of all registers. will be initialized in init_cg(),
+ register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+ estimated cost-saving can be obtained by several registers, the
+ one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle = {0, 0};
+
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+#define ISCOMPOSITE(t) (ISARRAY(t) || ISSTRUCT(t) || ISUNION(t))
+
+// number of registers to use, this can be a ny value from 3 to 14.
+// A value < 6 is not recommended as it does not leave any registers for
+// efficient code generation.
+// The default is 6.
+int nregs;
+
+// register names
+#define REG_FLAGS 1
+#define REG_SP 2
+#define REG_R0 3
+#define REG_R1 4
+#define REG_R2 5
+#define REG_R3 6
+#define REG_R4 7
+#define REG_R5 8
+#define REG_R6 9
+#define REG_R7 10
+#define REG_R8 11
+#define REG_R9 12
+#define REG_R10 13
+#define REG_R11 14
+#define REG_R12 15
+#define REG_R13 16
+
+// register usage tracking system
+// Allocated by ALLOCEG IC
+#define TRACK_ALLOCREG 1
+// used by IC, not available as temporary
+#define TRACK_IC 2
+// allocated as temporary by tracker
+#define TRACK_TMP 4
+// saved
+#define TRACK_SAVED 8
+// not usable as indicated by CPU register layout
+#define TRACK_OFFLIMITS 16
+// dedicated temporary register
+#define TRACK_DEDICATED 32
+// bits indicating register is used and cannot be used no matter what
+#define TRACK_NOGO (TRACK_IC | TRACK_TMP | TRACK_OFFLIMITS)
+int track_status[MAXR+1];
+
+// We provide 3 slots for temporary registers.
+// In here we keep track if which slot contains which register.
+#define TRACK_SLOTS 3
+int track_slot[TRACK_SLOTS];
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp = { INT };
+
+/* macros defined by the backend */
+// extended data types attribute strings
+#define EXTDATA_INTERRUPT "interrupt"
+
+static char *marray[] = {
+ "__FALCO16__",
+ "__interrupt(x)=__vattr(\"interrupt(\"#x\")\")",
+ 0
+};
+
+/* sections */
+#define SEC_TEXT 0 // code
+#define SEC_RODATA 1 // constant data
+#define SEC_DATA 2 // initialized data
+#define SEC_BSS 3 // data initialized to 0
+#define SEC_VECTOR 4 // irq vectors
+static int section = -1;
+static char *sec_textname = "code",
+ *sec_rodataname = "const",
+ *sec_dataname = "idata",
+ *sec_bssname = "zdata",
+ *sec_vectorname = "vector";
+
+/* assembly-prefixes for labels and external identifiers */
+static char *label_prefix = "p";
+static char *ident_prefix = "_";
+static int label_count;
+
+
+// assemly data storage strings
+static char *dct[] = {"", "db", "dw", "dw", "dd", "dd", "dd", "dd", "dd"};
+
+
+static long loff;
+static long stackoffset;
+static int newobj;
+
+
+static long pof2(zumax x)
+/* Yields log2(x)+1 oder 0. */
+{
+ zumax p;
+ int ln = 1;
+
+ p = ul2zum(1UL);
+ while (ln <= 32 && zumleq(p, x)) {
+ if (zumeqto(x, p)) return ln;
+ ln++; p = zumadd(p, p);
+ }
+ return 0;
+}
+
+static long const_get(struct obj *x, int typ, int n)
+{
+ long ret;
+
+ eval_const(&x->val, typ);
+ ret = (vmax >> (n * char_bit)) & 0xffff;
+
+ return ret;
+}
+
+static long ofs_get(struct obj *x)
+{
+ long ret;
+
+ ret = 0;
+ if (x->flags & VAR) {
+ if (x->v->offset < 0) {
+ ret = (long)(loff-(x->v->offset+2)+(x->val.vmax))-stackoffset+2;
+ } else {
+ ret = (long)((x->v->offset)+(x->val.vmax)-stackoffset);
+ }
+ }
+ return ret;
+}
+
+
+static void emit_object(FILE *f, struct obj *x, int n, int typ)
+{
+ long ofs;
+
+// calculate offset into stack
+ ofs = ofs_get(x);
+
+// access mode
+ eval_const(&x->val, typ);
+
+ if (x->flags & REG) {
+ if (x->flags & DREFOBJ) {
+// register pointer '[reg+ofs]'
+ emit(f, "[%s+%ld]", regnames[x->reg], n);
+ } else {
+// register 'reg'
+ emit(f, "%s", regnames[x->reg]);
+ }
+ } else if (x->flags & KONST) {
+ if (x->flags & VARADR) {
+// This is the special case for which the address of a constant must be generated.
+// KONST| VARADR is never generated by the front-end, but it's a modified
+// object by the back-end. The address of a constant is used for FLOAT/DOUBLE
+// library call operations involving a constant. An address to a constant is generated by
+// placing the constant into section SEC_RODATA and generating a pointer to
+// the object.
+// NOT COMPLETE, must have some kind of konst counter.
+// 1st nject konst into ROM section
+ emit(f, "__KONST_");
+ } else if (x->flags & DREFOBJ) {
+// constant address, e.g. mov [123], r0
+ emit(f, "[%ld]", const_get(x, typ, n));
+ } else {
+// regular KONST value
+ emit(f, "%ld", const_get(x, typ, n));
+ }
+ } else if (x->flags & VAR) {
+// REGULAR VARIABLE ACCESS
+ if (isauto(x->v->storage_class)) {
+ if (x->flags & VARADR) {
+// this is a special case not generated by the front-end, it's a modified object
+// by the back end needing to generate the address of a auto variable.
+// This is used by 'ptr_push'. What eventually must be generated is
+// mov reg, sp
+// add reg, ofs+n
+// Since this is the emit_object function we only generate sp here, the
+// add reg, ofs+n must be generated by the callee.
+ emit(f, "sp");
+ } else {
+// stack based value '[sp+ofs]'
+ emit(f, "[sp+%ld]", (long)ofs + n);
+ }
+ } else if (isextern(x->v->storage_class)) {
+ if (x->flags & VARADR) {
+// address of global variable
+ emit(f, "%s%s+%ld", ident_prefix, (long)x->v->identifier, (long)x->val.vmax + n);
+ } else {
+// value of global '[ident+ofs]'
+ emit(f, "[%s%s+%ld]", ident_prefix, (long)x->v->identifier, (long)x->val.vmax + n);
+ }
+ } else if (isstatic(x->v->storage_class)) {
+ if (x->flags & VARADR) {
+// address of static variable
+ emit(f, "%s%ld+%ld", label_prefix, (long)x->v->offset, (long)x->val.vmax + n);
+ } else {
+// value of static variable
+ emit(f, "[%s%ld+%ld]", label_prefix, (long)x->v->offset, (long)x->val.vmax + n);
+ }
+ } else terror("-- emit_object: unexpected storage class");
+ } else {
+ terror("-- emit_object: unexpected access mode");
+ }
+}
+
+/*
+Load a temporary ptr register to be used by the main emit_load
+function.
+returns 1, if code was generated to load the pointer.
+returns 0, if no code was necessary since no temporary ptr is required.
+*/
+static int emit_tmpptr(FILE *f, struct obj *x, int n)
+{
+ struct AddressingMode *am;
+ char *regptr_name;
+ int ret;
+
+ ret = 0;
+ am = x->am;
+ if (am && am->regptr) {
+ ret = 1;
+ regptr_name = regnames[x->am->regptr];
+ if (n == 0) {
+ emit(f, "\tmov\t%s, ", regptr_name);
+ emit_object(f, x, 0, POINTER);
+ emit(f, "\n");
+ } else {
+ // emit(f, "\tadd\t%s, %d\n", regptr_name, n);
+ }
+ }
+ return ret;
+}
+
+
+// Generate code to perform a given operation.
+// The code generated is:
+// op t, s
+// typ = operand type (e.g CHAR, POINTER, INT ...)
+// n = the offset when dealing with multi-world objects (e.g long, float)
+// EITHER t OR s MUST BE A REGISTER!
+// For the non-register operand, temporaries are used and loaded
+// according to am-data.
+static void emit_op(FILE *f, struct obj *t, struct obj *s, int typ, int n, char *op)
+{
+ long ofs;
+ char *mode;
+
+// calculate offset into stack
+ ofs = ofs_get(t);
+
+// determine access mode (8-bit or 16-bit instruction)
+ mode = "";
+ if (sizetab[typ&NQ] == 1) mode = ".8";
+
+ if (emit_tmpptr(f, s, n)) {
+// we use a temporary pointer and it's loaded in register s->am->regptr
+// Now we have to generate the code to load the data using the temporary pointer.
+ emit(f, "\t%s%s\t%s, [%s+%d]\n", op, mode, regnames[t->reg], regnames[s->am->regptr], n);
+ } else if (emit_tmpptr(f, t, n)) {
+// get value into target register
+ emit(f, "\t%s%s\t[%s+%d], %s\n", op, mode, regnames[t->am->regptr], n, regnames[s->reg]);
+ } else {
+ emit(f, "\t%s%s\t", op, mode);
+ emit_object(f, t, n, typ);
+ emit(f, ", ");
+ emit_object(f, s, n, typ);
+ emit(f, "\n");
+ }
+}
+
+// Generate register loading code in the following format:
+// op reg, x
+// Meaning it is always code generated, which loads into a register.
+// typ = operand type (e.g CHAR, POINTER, INT ...)
+// n = the offset when dealing with multi-world objects (e.g long, float)
+static void emit_load(FILE *f, int reg, struct obj *s, int typ, int n, char *op)
+{
+ struct obj *x;
+ int ofs;
+
+// if target register is blank, we quit
+ if (reg == 0) return;
+
+ x = mymalloc(sizeof(struct obj));
+
+// build a target register object
+ x->flags = REG;
+ x->reg = reg;
+ x->dtyp = 0;
+ x->v = 0;
+ x->am = 0;
+
+// generate operation
+ emit_op(f, x, s, typ, n, op);
+// we have to take care of the speical case of address of auto variable
+ if ((s->flags & (VAR|VARADR)) == (VAR|VARADR)) {
+ if (isauto(s->v->storage_class)) {
+// calculate offset into stack
+ ofs = ofs_get(s) + n;
+ if (ofs) {
+ emit(f, "\tadd\t%s, %d\n", regnames[reg], ofs);
+ }
+ }
+ }
+
+ myfree(x);
+}
+
+// Generate the following code:
+// mov t, reg
+// typ = operand type (e.g CHAR, POINTER, INT ...)
+// n = the offset when dealing with multi-world objects (e.g long, float)
+static void emit_store(FILE *f, struct obj *t, int reg, int typ, int n)
+{
+ struct obj *x;
+
+// if source register is blank, we quit
+ if (reg == 0) return;
+
+ x = mymalloc(sizeof(struct obj));
+
+// build a source register object
+ x->flags = REG;
+ x->reg = reg;
+ x->dtyp = 0;
+ x->v = 0;
+ x->am = 0;
+
+// generate operation
+ emit_op(f, t, x, typ, n, "mov");
+
+ myfree(x);
+}
+
+void am_alloc(struct obj *x)
+{
+// if no object, return
+ if (x == 0) return;
+// if already allocated, return
+ if (x->am) return;
+
+ x->am = mymalloc(sizeof(struct AddressingMode));
+ x->am->regptr = 0;
+ x->am->regval[0] = 0;
+ x->am->regval[1] = 0;
+}
+
+// Compare if 2 objects are the same.
+int obj_eq(struct obj *x1, struct obj *x2)
+{
+ int ret;
+
+// we assume the objects are equal to start with
+ ret = 1;
+
+ if (x1==0 || x2==0) {
+ ret = 0;
+ } else {
+ if (x1->flags != x2->flags) ret = 0;
+ if (x1->reg != x2->reg) ret = 0;
+ }
+
+ return ret;
+}
+
+/*
+Initialize register tracking system.
+The tracking systemis is used to keep track of what register is used and holds
+what at any given time. Depending on availability, temporary registers can be
+allocated with best efficiency.
+*/
+static void track_init(void)
+{
+ int i;
+
+// pre-fill
+ for(i = 1; i <= MAXR; i++) {
+// clear all unnecessary bits
+ track_status[i] &= (TRACK_OFFLIMITS | TRACK_DEDICATED);
+ }
+
+// all slots are empty at the beginning.
+ for (i = 0; i < TRACK_SLOTS; i++) {
+// indicate slot is not used
+ track_slot[i] = 0;
+ }
+}
+
+
+// Mark any register used by the IC
+static void track_obj_claim(struct obj *x)
+{
+// analyze object and flag already used registers as 'no-go'
+ if (x && (x->flags & REG)) {
+ track_status[x->reg] |= TRACK_IC;
+ }
+}
+
+/*
+Allocate the required temporary registers
+to be able to generate code for the given IC.
+Each operand gets an 'am' datastructure, which
+is filled with the temporary registers to use.
+
+And it works like this
+z = q1 <op> q2
+ptr ptr ptr
+val val
+
+There's only one ptr that satisfies all three operand.
+There's only one val that is used for both q1 and z.
+
+So for example in if we have q1(ptr, val) that means:
+Use register ptr to get q1 into register val.
+
+Or for z(ptr, val): Use register ptr to store register val
+to the target location.
+*/
+
+
+/*
+0. determine if we need to free previously allocated temps
+a. we do this if we got a branch or if the current IC uses any temp reg
+1. determine how many temporaries we need
+2. check if we can reuse previously reserved temps
+3. reserve temps if necessary (and make it smart, pick the ones that are not used in the next IC)
+*/
+
+static int track_alloc(FILE *f)
+{
+ int reg;
+ int i;
+ int save;
+
+ reg = 0;
+ save = 0;
+// try to find a register
+// If we can't find one, there's some serious issue.
+ for (i = 1; i < MAXR+1; i++) {
+ if ((track_status[i] & (TRACK_NOGO|TRACK_ALLOCREG|TRACK_SAVED)) == TRACK_ALLOCREG) {
+// found a register, but it must be saved, keep looking maybe
+// we find a better one, only use this if we haven't found anything useful yet
+ if (reg == 0) {
+ reg = i;
+ save = 1;
+ }
+ } else if ((track_status[i] & (TRACK_NOGO|TRACK_ALLOCREG|TRACK_SAVED)) == (TRACK_ALLOCREG|TRACK_SAVED)) {
+// found a register, it's in use by ALLOCREG, but it has already been saved
+// We use it and quit.
+ reg = i;
+ save = 0;
+ break;
+ } else if ((track_status[i] & (TRACK_NOGO|TRACK_ALLOCREG|TRACK_SAVED|TRACK_DEDICATED)) == 0) {
+// found an unallocated register which is not a dedicated temp, we use it
+ reg = i;
+ save = 0;
+ break;
+ } else if ((track_status[i] & (TRACK_NOGO|TRACK_DEDICATED)) == TRACK_DEDICATED) {
+// found a dedicated temporary, we could use it, but we try to find a better one
+ reg = i;
+ save = 0;
+ }
+ }
+ if (reg == 0) terror("-- track_alloc: can't find temporary register");
+
+// flag register as taken
+ track_status[reg] |= TRACK_TMP;
+ emit(f, "; allocate temporary: %s\n", regnames[reg]);
+ if (save) {
+ track_status[reg] |= TRACK_SAVED;
+// find an unused storage slot
+ for (i = 0; i < TRACK_SLOTS; i++) {
+ if (!track_slot[i]) break;
+ }
+ if (i >= TRACK_SLOTS) terror("--track_alloc: out of storage slots");
+ track_slot[i] = reg;
+ emit(f, "\tmov\t[_TSLOT+%d], %s\n", i*2, regnames[reg]);
+ }
+
+ return reg;
+}
+
+
+/*
+Temporary register tracking and assignement.
+*/
+/*
+Check if access to object x requires temporary registers.
+Allocate all required temporary registers.
+*/
+static void track_obj(FILE *f, struct obj *x, int typ)
+{
+ int i;
+ int reg, reg2;
+ int need_tmpval;
+ int size;
+
+
+// object must have 'am' structure.
+ am_alloc(x);
+
+// determine if we need to free previously allocated temporaries
+// claim registers used by object
+ track_obj_claim(x);
+// see if one of them was allocated, and free it if necessary
+ for (i = 0; i < TRACK_SLOTS; i++) {
+ reg = track_slot[i];
+ if ((track_status[reg] & (TRACK_IC|TRACK_SAVED)) == (TRACK_IC|TRACK_SAVED)) {
+ track_status[reg] &= ~TRACK_SAVED;
+ track_slot[i] = 0;
+ emit(f, "; restore temporary\n");
+ emit(f, "\tmov\t%s, [_TSLOT+%d]\n", regnames[reg], i*2);
+ }
+ }
+
+// determine how many temporary registers we need
+ need_tmpval = 1;
+ if (x && (x->flags & (REG|DREFOBJ)) == REG) need_tmpval = 0;
+
+ if (need_tmpval) {
+// we need temporary value register, allocate one
+ reg = track_alloc(f);
+// In case this is a 32-bit operand we need 2 temporaries
+ size = sizetab[typ&NQ];
+ reg2 = 0;
+ if (size == 4) {
+ reg2 = track_alloc(f);
+ }
+ x->am->regval[0] = reg;
+ x->am->regval[1] = reg2;
+ }
+
+// next step is to check if pointer memory access requires a register
+ if (x && (x->flags & (DREFOBJ | VAR | REG)) == (DREFOBJ | VAR)) {
+ reg = track_alloc(f);
+ x->am->regptr = reg;
+ }
+}
+
+/*
+Check the IC for temporary register requirements.
+Allocate all required temporaries and save them if required.
+*/
+static void track_ic(FILE *f, struct IC *p)
+{
+ struct obj *z;
+ struct obj *q1;
+ struct obj *q2;
+ int i;
+ int reg, reg2;
+ int need_tmpval;
+ int size;
+ int code;
+
+// get objects
+ z = &p->z;
+ q1 = &p->q1;
+ q2 = &p->q2;
+
+// get instruction code
+ code = p->code;
+
+// each object must have 'am' structure.
+ am_alloc(z);
+ am_alloc(q1);
+ am_alloc(q2);
+
+
+// determine if we need to free previously allocated temporaries
+// claim registers used by IC
+ track_obj_claim(z);
+ track_obj_claim(q1);
+ track_obj_claim(q2);
+
+// see if one of them was allocated, and free it if necessary
+ for (i = 0; i < TRACK_SLOTS; i++) {
+ reg = track_slot[i];
+ if ((track_status[reg] & (TRACK_IC|TRACK_SAVED)) == (TRACK_IC|TRACK_SAVED)) {
+ track_status[reg] &= ~TRACK_SAVED;
+ track_slot[i] = 0;
+ emit(f, "; restore temporary\n");
+ emit(f, "\tmov\t%s, [_TSLOT+%d]\n", regnames[reg], i*2);
+ }
+ }
+
+// determine how many temporary registers we need
+ need_tmpval = 1;
+ if (z && (z->flags & (REG|DREFOBJ)) == REG) need_tmpval = 0;
+ if (q1 && (q1->flags & (REG|DREFOBJ)) == REG) need_tmpval = 0;
+ if (q2 && (q2->flags & (REG|DREFOBJ)) == REG) need_tmpval = 0;
+
+// if target Z is NOT the same as Q1 we will always need a temporary
+ if (code == ASSIGN || code == CONVERT) {
+ ;
+ } else if (code == COMPARE) {
+// in case of COMPARE we need a temporary if Q1 == KONST
+ if (q1 && (q1->flags & KONST) == KONST) need_tmpval = 1;
+ } else {
+ if (!obj_eq(z, q1)) {
+ need_tmpval = 1;
+ }
+ }
+
+ if (need_tmpval) {
+ reg = 0;
+// check if we can use target register as temporary
+// We can do so if Q2 is not the same as Z
+ if (z) {
+ if (((z->flags & (REG|DREFOBJ)) == REG) && !obj_eq(z, q2)) {
+ reg = z->reg;
+ track_status[reg] |= TRACK_TMP;
+ } else {
+// we need temporary value register, allocate one
+ reg = track_alloc(f);
+ }
+// In case this is a 32-bit operand we need 2 temporaries
+ size = sizetab[ztyp(p)&NQ];
+ reg2 = 0;
+ if (size >= 4) {
+ reg2 = track_alloc(f);
+ }
+ z->am->regval[0] = reg;
+ z->am->regval[1] = reg2;
+ }
+// Q1 need the same temp as Z, but maybe only 16-bit
+ if (q1) {
+ if (!reg) {
+ reg = track_alloc(f);
+ }
+ q1->am->regval[0] = reg;
+ if (sizetab[q1typ(p)&NQ] <= 2) {
+ reg2 = 0;
+ }
+ q1->am->regval[1] = reg2;
+ }
+ }
+
+// next step is to check if pointer memory access requires a register
+ reg = 0;
+ if (z && (z->flags & (DREFOBJ | VAR | REG)) == (DREFOBJ | VAR)) {
+ if (!reg) reg = track_alloc(f);
+ z->am->regptr = reg;
+ }
+ if (q1 && (q1->flags & (DREFOBJ | VAR | REG)) == (DREFOBJ | VAR)) {
+ if (!reg) reg = track_alloc(f);
+ q1->am->regptr = reg;
+ }
+ if (q2 && (q2->flags & (DREFOBJ | VAR | REG)) == (DREFOBJ | VAR)) {
+ if (!reg) reg = track_alloc(f);
+ q2->am->regptr = reg;
+ }
+
+}
+
+static void track_release(void)
+{
+ int i;
+
+ for (i = 1; i <= MAXR; i++) {
+ track_status[i] &= ~(TRACK_TMP|TRACK_IC);
+ }
+}
+
+/*
+Restores all saved temporary registers.
+This must be executed before any branch, call
+or function exit.
+*/
+static void track_restore(FILE *f)
+{
+ int i;
+
+ track_release();
+ for (i = 0; i < TRACK_SLOTS; i++) {
+ if (track_slot[i]) {
+ track_status[track_slot[i]] &= ~(TRACK_SAVED);
+ emit(f, "\tmov\t%s, [_TSLOT+%d]\n", regnames[track_slot[i]], i*2);
+ track_slot[i] = 0;
+ }
+ }
+}
+// same as above, but don't clear TRACK_SAVED and don't release the temps.
+// This is used in branch instructions.
+static void track_restore2(FILE *f)
+{
+ int i;
+
+ for (i = 0; i < TRACK_SLOTS; i++) {
+ if (track_slot[i]) {
+ emit(f, "\tmov\t%s, [_TSLOT+%d]\n", regnames[track_slot[i]], i*2);
+ }
+ }
+}
+
+
+
+/* generates the function entry code */
+static void cd_function_entry(FILE *f, struct Var *v, long offset)
+{
+ int i;
+
+ if (section != SEC_TEXT) {
+ emit(f, "\n\tsection\t%s\n", sec_textname);
+ section = SEC_TEXT;
+ }
+
+ if (v->storage_class == EXTERN) emit(f,"\tpublic\t%s%s\n", ident_prefix, v->identifier);
+ emit(f,"%s%s:\n", ident_prefix,v->identifier);
+
+ if (v->vattr && strstr(v->vattr, EXTDATA_INTERRUPT)) {
+// interrupt service routine
+ emit(f, "\tpush\tflags\n");
+ for (i = REG_R0; i < REG_R0+nregs; i++) {
+ emit(f, "\tpush\t%s\n", regnames[i]);
+ }
+ }
+
+// allocate required stack
+ if (offset > 0) emit(f,"\tsub\tsp, %ld\n", offset);
+
+// store non-scratch register used in function
+ for (i = 1; i <= MAXR; i++) {
+ if (!regsa[i] && !regscratch[i] && regused[i]) {
+ emit(f, "\tpush\t%s\n", regnames[i]);
+// adjust stack offset
+ stackoffset -= 2;
+ }
+ }
+}
+
+/* generates the function exit code */
+static void cg_function_exit(FILE *f, struct Var *v, long offset)
+{
+ int i;
+
+// restore any saved temporary registers
+// I don't think this is necessary as long as we don't have global register variables.
+// What does vbcc do? Global regs?
+ track_restore(f);
+
+// restore non-scratch register used in function
+ for (i = MAXR; i >= 1; i--) {
+ if (!regsa[i] && !regscratch[i] && regused[i]) {
+ emit(f, "\tpop\t%s\n", regnames[i]);
+ stackoffset += 2;
+ }
+ }
+
+ if (offset > 0) {
+ emit(f,"\tadd\tsp, %ld\n", offset);
+ }
+
+ if (v->vattr && strstr(v->vattr, EXTDATA_INTERRUPT)) {
+// interrupt service routine
+ for (i = REG_R0+nregs-1; i >= REG_R0; i--) {
+ emit(f, "\tpop\t%s\n", regnames[i]);
+ }
+ emit(f, "\tpop\tflags\n");
+ emit(f, "\tiret\n\n");
+ } else {
+ emit(f, "\tret\n\n");
+ }
+}
+
+/*
+some blurp:
+There's an IC, which contains a target(z), and 2 sources(q1 and q2).
+Macros ztyp, q1typ and q2typ return the type of the operands
+e.g. (char, int, short, double, struct, array....).
+Also contains the qualifiers UNSIGNED, CONST
+Most of the time it's the same for all operands. Exceptions are
+CONVERT or adding int to pointer.
+Using NU and NQ will remove qualifiers and only leave base type.
+
+Of interest are:
+ISPOINTER, ISINT, ISFLOAT, ISFUNC, ISSTRUCT, ISUNION, ISARRAY,
+ISSCALAR, ISARITH
+
+Each operand can be one of the following:
+----------------------------------------
+KONST constant number
+KONST|DREFOBJ absolute pointer
+REG register
+VAR variable (can be auto, register, static, extern)
+VAR|REG a variable which was put in a register
+REG|DREFOBJ indirect [reg]
+VAR|DREFOBJ indirect [var]
+VAR|REG|DREFOBJ indirect [reg], where the register is a variable
+VAR|VARADR address of a variable
+
+Temporaries generated by the compiler don't have the VAR flag set.
+It is only a VAR if it is so in the source code.
+
+Each variable then has information regarding the storage class,
+so each VAR is on of the following:
+AUTO
+REGISTER
+STATIC
+EXTERN
+
+Macros of interest:
+isauto, isextern, isstatic.
+
+*/
+/* val_push
+Pushing the value of the object onto the stack.
+*/
+static void val_push(FILE *f, struct obj *x, int typ)
+{
+// handle required temporaries
+ track_obj(f, x, typ);
+
+ emit(f, "; push val\n");
+
+// Load Q1 into temporary register val if necessary.
+// Automatically use temporary x->am->regptr if necessary.
+ emit_load(f, x->am->regval[0], x, typ, 0, "mov");
+ emit_load(f, x->am->regval[1], x, typ, 2, "mov");
+
+// emit operation
+ if (x->am->regval[1]) {
+ emit(f, "\tpush\t%s\n", regnames[x->am->regval[1]]);
+ stackoffset -= 2;
+ }
+ if (x->am->regval[0]) {
+// operation is performed on temporaries
+ emit(f, "\tpush\t%s\n", regnames[x->am->regval[0]]);
+ stackoffset -= 2;
+ } else {
+// operation is performed directly on target (z == q1 for this to work)
+ emit(f, "\tpush\t%s\n", regnames[x->reg]);
+ stackoffset -= 2;
+ }
+
+// release temporaries
+ track_release();
+}
+/* ptr_push
+Pushing the ptr to the object onto the stack.
+In case the object is a KONST, a copy of the KONST is made
+in romsection and a pointer to the constant is pushed.
+WARNING WARNING WARNING
+This function MODIFIES the object *x.
+*/
+static void ptr_push(FILE *f, struct obj *x)
+{
+// handle required temporaries
+ track_obj(f, x, POINTER);
+
+ emit(f, "; push ptr to object\n");
+
+// modify the IC such that we can generate code from it
+
+// what we should do here is: if DREFOBJ is set, clear it. If DREFOBJ is not set, set VARADR.
+ if (x->flags & DREFOBJ) {
+ x->flags &= ~DREFOBJ;
+ } else {
+ x->flags |= VARADR;
+ }
+ x->dtyp = POINTER;
+
+// Load object into temporary register val if necessary.
+// Automatically use temporary x->am->regptr if necessary.
+ emit_load(f, x->am->regval[0], x, POINTER, 0, "mov");
+
+// emit operation
+ if (x->am->regval[0]) {
+// operation is performed on temporaries
+ emit(f, "\tpush\t%s\n", regnames[x->am->regval[0]]);
+ stackoffset -= 2;
+ } else {
+// operation is performed directly on target (z == q1 for this to work)
+ emit(f, "\tpush\t%s\n", regnames[x->reg]);
+ stackoffset -= 2;
+ }
+
+// release temporaries
+ track_release();
+}
+
+/*
+Get the object from the stack. It is assumed the object is
+located at [sp]. It is subsequently transfered to x
+[sp] --> x
+This function can be implemented either using 'pop' or using '[sp+xx]'.
+Either one has advantage or disadvantage, also depending on CPU
+implementation.
+*/
+void val_pop(FILE *f, struct obj *x, int typ)
+{
+ emit(f, "; pop val\n");
+
+// handle required temporaries
+ track_obj(f, x, typ);
+
+// Load [sp] value into temporary register val if necessary.
+ if (x->am->regval[0]) {
+// operation is performed on temporaries
+ emit(f, "\tpop\t%s\n", regnames[x->am->regval[0]]);
+ stackoffset += 2;
+ if (x->am->regval[1]) {
+ emit(f, "\tpop\t%s\n", regnames[x->am->regval[1]]);
+ stackoffset += 2;
+ }
+ } else {
+// operation is performed directly on target (z == q1 for this to work)
+ emit(f, "\tpop\t%s\n", regnames[x->reg]);
+ stackoffset += 2;
+ }
+
+// store to target
+ emit_store(f, x, x->am->regval[0], typ, 0);
+ emit_store(f, x, x->am->regval[1], typ, 2);
+
+// release temporaries
+ track_release();
+}
+
+/*
+Library call for ALU functions.
+*/
+static void lib_alu(FILE *f, struct IC *p, char *call)
+{
+ char *modifier;
+ char *dtype;
+ int size;
+
+ // do some checking first
+ if (q1typ(p) != q2typ(p)) terror("--lib_alu: type mismatch");
+
+ modifier = "S";
+ if (q1typ(p) & UNSIGNED) {
+ modifier = "U";
+ }
+
+ switch (q1typ(p)) {
+ case CHAR:
+ dtype = "I8"; break;
+ case SHORT:
+ case INT:
+ dtype = "I16"; break;
+ case LONG:
+ dtype = "I32"; break;
+ case FLOAT:
+ dtype = "F32"; break;
+ case DOUBLE:
+ dtype = "F64"; break;
+ default:
+ dtype = ""; break;
+ terror("--lib_alu: data type not supported");
+ break;
+ }
+// handle required temporaries
+// temporary allocation is handled in val_push instead.
+// The idea here is to allocate all required temporaries now,
+// such that the return value can be easily grabbed.
+// This is not implemented right now due to complications.
+// track_ic(f, p);
+
+// push the spaceholder for the result
+ size = sizetab[ztyp(p)&NQ];
+ if (size <= 2) {
+// stack is 2-byte minimum
+ if (size < 2) size = 2;
+ emit(f, "\tsub\tsp, %d\n", size);
+ stackoffset -= size;
+// Push all arguments
+ val_push(f, &p->q2, q2typ(p));
+ val_push(f, &p->q1, q1typ(p));
+ } else {
+ ptr_push(f, &p->q2);
+ ptr_push(f, &p->q1);
+ }
+ track_restore(f);
+// emit call to library function
+ emit(f, "\tcall\t_%s_%s%s\n", call, modifier, dtype);
+
+// restore stack state
+// use 2*size in case 'val_pop' actually pops,
+// use 3*size in case 'val_pop uses [sp+xx]
+ emit(f, "\tadd\tsp, %d\n", (int)2*size);
+ stackoffset += 2*size;
+
+// last step is to grab the return value
+// Return value is at [sp].
+ val_pop(f, &p->z, ztyp(p));
+
+}
+
+
+/*
+Library call for mempry copy functions.
+*/
+static void lib_mov(FILE *f, struct IC *p)
+{
+
+// modify the IC such that we can generate code from it
+ p->q2.flags = KONST;
+
+// Push Q2 (number of bytes to copy)
+ emit(f, "; push array size\n");
+ val_push(f, &p->q2, INT);
+// Push pointer to Q1 (source)
+ emit(f, "; push source pointer\n");
+ ptr_push(f, &p->q1);
+// push pointer to target (Z)
+ emit(f, "; push target pointer\n");
+ ptr_push(f, &p->z);
+
+ track_restore(f);
+// emit call to library function
+ emit(f, "\tcall\t_MOV\n");
+
+// stack cleanup, we should use callee clean-up
+ emit(f, "\tadd\tsp, %d\n", (int)6);
+ stackoffset += 6;
+}
+/*
+
+*/
+static void cg_assign(FILE *f, struct IC *p)
+{
+ struct obj *x;
+ int typ;
+ int size;
+
+// any struct or array goes to library function
+// anything > 4 bytes goes to library
+// size is only possible with ASSIGN, not CONVERT.
+ if (p->code == ASSIGN) {
+ size = opsize(p);
+ if (size > 4 || ISCOMPOSITE(ztyp(p))) {
+
+ lib_mov(f, p);
+ return;
+ }
+ }
+
+// handle required temporaries
+ track_ic(f, p);
+
+ // We also get here for CONVERT, so test don't work.
+ // if (q1typ(p) != ztyp(p)) terror(0);
+ emit(f, "; mov\n");
+
+// emit operation
+ typ = q1typ(p);
+ x = &p->q1;
+ if (x->am->regval[0]) {
+// operation is performed on temporaries
+ emit_load(f, x->am->regval[0], x, typ, 0, "mov");
+ emit_load(f, x->am->regval[1], x, typ, 2, "mov");
+ } else {
+// operation is performed directly, no temporaries involved
+ emit_op(f, &p->z, x, typ, 0, "mov");
+ }
+
+// check if this is a CONVERT operation and inject sign extension
+// if necessary.
+ if (p->code == CONVERT) {
+// if Q1 is CHAR we need to blow it up to INT
+ if (sizetab[q1typ(p) & NQ] == 1) {
+ if (typ & UNSIGNED) {
+// clear high byte
+ if (p->z.am->regval[0]) {
+ emit(f, "\tand\t%s, 0xff\n", regnames[p->z.am->regval[0]]);
+ } else {
+ emit(f, "\tand\t%s, 0xff\n", regnames[p->z.reg]);
+ }
+ } else {
+// SXT high byte
+ if (p->z.am->regval[0]) {
+ emit(f, "\tsxt.8\t%s\n", regnames[p->z.am->regval[0]]);
+ } else {
+ emit(f, "\tsxt.8\t%s\n", regnames[p->z.reg]);
+ }
+ }
+ }
+// if Z is LONG we need to blow it up from INT to LONG
+ if (sizetab[ztyp(p) & NQ] == 4) {
+ if (typ & UNSIGNED) {
+ emit(f, "\tmov\t%s, 0\n", regnames[p->z.am->regval[1]]);
+ } else {
+ emit(f, "\tmov\t%s, %s\n", regnames[p->z.am->regval[1]], regnames[p->z.am->regval[0]]);
+ emit(f, "\tsxt\t%s\n", regnames[p->z.am->regval[1]]);
+ }
+ }
+ }
+// emit store if necessary
+ typ = ztyp(p);
+ x = &p->z;
+ emit_store(f, x, x->am->regval[0], typ, 0);
+ emit_store(f, x, x->am->regval[1], typ, 2);
+
+// release temporaries
+ track_release();
+}
+
+
+static void cg_push(FILE *f, struct IC *p)
+{
+ int size;
+
+// any object larger than 4 bytes goes to a library function
+ size = opsize(p); // might need to use pushsize here instead of opsize?
+ if (size > 4 || ISCOMPOSITE(q1typ(p))) {
+// allocate required stack
+ emit(f, "\tsub\tsp, %d\n", size);
+ stackoffset -= size;
+
+// Push Z (number of bytes to push)
+ emit(f, "; push array size\n");
+// modify z such that it becomes a KONST
+ p->z.flags = KONST;
+ val_push(f, &p->z, INT);
+// Push pointer to Q1 (source)
+ emit(f, "; push source pointer\n");
+ ptr_push(f, &p->q1);
+
+// emit call to library function
+ emit(f, "\tcall\t_PUSH\n");
+
+// stack cleanup, we should use callee clean-up
+ emit(f, "\tadd\tsp, %d\n", (int)4);
+ stackoffset += 4;
+ return;
+ }
+// handle required temporaries of 1op instructions
+ // track_push(f, p); // this must go, needs to be part of val_push
+
+ val_push(f, &p->q1, q1typ(p));
+
+}
+
+static void cg_call(FILE *f, struct IC *p)
+{
+ long size = pushedargsize(p);
+ long ofs;
+
+// calculate offset into stack
+ ofs = ofs_get(&p->q1);
+
+ emit(f, "; call\n");
+
+// restore any temporaries
+ track_restore(f);
+
+ if ((p->q1.flags & (VAR|DREFOBJ)) == VAR) {
+// call to label
+ emit(f, "\tcall\t%s%s\n", ident_prefix, p->q1.v->identifier);
+ } else if ((p->q1.flags & (VAR|DREFOBJ)) == (VAR|DREFOBJ) && p->q1.dtyp == POINTER) {
+ terror("-- call: pointer argument not yet supported");
+ } else terror("-- call: unexpected call mode\n");
+ if (size > 0) {
+ emit(f,"\tadd\tsp, %ld\n", size);
+ stackoffset += size;
+ }
+}
+
+
+static void cg_alu(FILE *f, struct IC *p)
+{
+ struct obj *x;
+ int typ;
+ int c;
+ char *instr1, *instr2;
+
+ c = p->code;
+ switch (c) {
+ case ADD: instr1 = "add"; instr2 = "addc"; break;
+ case SUB: instr1 = "sub"; instr2 = "subc"; break;
+ case ADDI2P: instr1 = "add"; instr2 = "addc"; break;
+ case SUBIFP: instr1 = "sub"; instr2 = "subc"; break;
+ case OR: instr1 = instr2 = "or"; break;
+ case AND: instr1 = instr2 = "and"; break;
+ case XOR: instr1 = instr2 = "xor"; break;
+ default: instr1 = "xxx"; break;
+ };
+
+ emit(f, "; %s\n", instr1);
+
+ // get type of argument
+ typ = ztyp(p);
+
+// try to get z and q1 the same, if possible
+ switch_IC(p);
+// handle required temporaries of 2op instructions
+ track_ic(f, p);
+
+
+ if (!ISINT(typ) && !ISPOINTER(typ)) terror("-- addsub: unexpected operands");
+
+// Load Q1 into temporary register val if necessary.
+// Automatically use temporary x->am->regptr if necessary.
+ x = &p->q1;
+ emit_load(f, x->am->regval[0], x, typ, 0, "mov");
+ emit_load(f, x->am->regval[1], x, typ, 2, "mov");
+
+// emit operation
+ x = &p->z;
+ if (x->am->regval[0]) {
+// operation is performed on temporaries
+ emit_load(f, x->am->regval[0], &p->q2, typ, 0, instr1);
+ emit_load(f, x->am->regval[1], &p->q2, typ, 2, instr2);
+ } else {
+// operation is performed directly on target (z == q1 for this to work)
+ emit_op(f, x, &p->q2, typ, 0, instr1);
+ }
+
+// emit store if necessary
+ x = &p->z;
+ if (x->am->regval[0]) {
+ if (((x->flags & (REG|DREFOBJ)) != REG) && x->reg != x->am->regval[0]) {
+// only write store if target is not a register or in case it is a register it
+// is not the same as the source.
+ emit_store(f, x, x->am->regval[0], typ, 0);
+ emit_store(f, x, x->am->regval[1], typ, 2);
+ }
+ }
+// release temporaries
+ track_release();
+}
+
+
+static void cg_lshift(FILE *f, struct IC *p)
+{
+// First we check if we can take a short-cut and don't need to
+// call the library.
+// [not done]
+
+ lib_alu(f, p, "SHL");
+}
+
+static void cg_rshift(FILE *f, struct IC *p)
+{
+// First we check if we can take a short-cut and don't need to
+// call the library.
+// [not done]
+
+ lib_alu(f, p, "SHR");
+}
+
+
+static void cg_mult(FILE *f, struct IC *p)
+{
+// First we check if we can take a short-cut and don't need to
+// call the library.
+// [not done]
+
+ lib_alu(f, p, "MUL");
+}
+
+static void cg_div(FILE *f, struct IC *p)
+{
+// First we check if we can take a short-cut and don't need to
+// call the library.
+// [not done]
+
+ lib_alu(f, p, "DIV");
+}
+
+static void cg_mod(FILE *f, struct IC *p)
+{
+// First we check if we can take a short-cut and don't need to
+// call the library.
+// [not done]
+
+ lib_alu(f, p, "MOD");
+}
+/*
+modify IC such that we get
+z = q1 xor 0xffff
+*/
+static void cg_komplement(FILE *f, struct IC *p)
+{
+ struct obj *x;
+
+ emit(f, "; komplement\n");
+
+ p->code = XOR;
+
+// change q2 to const 0
+ x = &p->q2;
+ x->flags = KONST;
+ x->reg = 0;
+ x->dtyp = 0;
+// insert 0xffff
+ gval.vmax = -1;
+ eval_const(&gval, MAXINT);
+ insert_const(&x->val, ztyp(p));
+
+// transfer to alu
+ cg_alu(f, p);
+}
+
+/*
+modify IC such that we get
+z = 0 - q1
+*/
+static void cg_minus(FILE *f, struct IC *p)
+{
+ struct obj *x;
+
+ emit(f, "; minus\n");
+
+ p->code = SUB;
+ p->q2 = p->q1;
+
+// change q1 to const 0
+ x = &p->q1;
+ x->flags = KONST;
+ x->reg = 0;
+ x->dtyp = 0;
+// is this the right way of generating a constant?
+ gval.vmax = 0;
+ eval_const(&gval, MAXINT);
+ insert_const(&x->val, ztyp(p));
+
+// transfer to alu
+ cg_alu(f, p);
+
+}
+
+static void cg_address(FILE *f, struct IC *p)
+{
+ struct obj *x;
+ int typ;
+ long ofs;
+ int reg;
+
+// calculate offset into stack
+ ofs = ofs_get(&p->q1);
+
+// handle required temporaries of 1op instructions
+ track_ic(f, p);
+
+ emit(f, "; address\n");
+
+// emit operation
+ typ = ztyp(p);
+ x = &p->z;
+ reg = x->reg;
+ if (x->am->regval[0]) {
+ reg = x->am->regval[0];
+ }
+// emit operation
+ emit(f, "\tmov\t%s, sp\n", regnames[reg]);
+ if (ofs != 0) emit(f, "\tadd\t%s, %ld\n", regnames[reg], ofs);
+
+// emit store if necessary
+ typ = ztyp(p);
+ x = &p->z;
+ if (x->am->regval[0]) {
+ if ((x->flags & (REG|DREFOBJ)) != REG) {
+// only write store if target is not a register
+ emit_store(f, x, x->am->regval[0], typ, 0);
+ }
+ }
+// release temporaries
+ track_release();
+}
+
+/*
+modify IC such that we get
+COMPARE q1, 0
+*/
+static void cg_test(FILE *f, struct IC *p)
+{
+ struct obj *x;
+
+ emit(f, "; test\n");
+
+ p->code = COMPARE;
+
+// change q2 to const 0
+ x = &p->q2;
+ x->flags = KONST;
+ x->reg = 0;
+ x->dtyp = 0;
+// insert 0
+ gval.vmax = 0;
+ eval_const(&gval, MAXINT);
+ insert_const(&x->val, ztyp(p));
+
+}
+
+/*
+Swap operands q1 <-> q2 of an IC. This is used by the branch IC
+to map the operation to the available comaprisons.
+*/
+static void swap_operands(struct IC *p)
+{
+ struct obj y;
+ y = p->q1;
+ p->q1 = p->q2;
+ p->q2 = y;
+}
+
+static void cg_branch_modify(struct IC *cmp, struct IC *p)
+{
+ int c;
+ int q2_inc;
+ int swap;
+ int q2_konst;
+
+
+// grab the branch instruction
+ c = p->code;
+
+/*
+In case Q1 == KONST we need to swap operands, however
+this only makes a difference in case Q2 == REG.
+This whole logic here might not be necessary if the front-end
+always puts KONST in Q2. Test seem to confirm this, however for
+the time being we leave the code in.
+*/
+ if (((cmp->q1.flags & (KONST|DREFOBJ)) == KONST) && ((cmp->q2.flags & (REG|DREFOBJ)) == REG)) {
+// swap operands
+ swap_operands(cmp);
+// modify branch condition to match operand swap
+ switch (c) {
+ case BLT: c = BGT; break;
+ case BGE: c = BLE; break;
+ case BLE: c = BGE; break;
+ case BGT: c = BLT; break;
+ }
+ }
+
+// Check if Q2 is a KONST. If it is we shouldn't swap operands.
+ q2_konst = 0;
+ if ((cmp->q2.flags & (KONST|DREFOBJ)) == KONST) {
+ q2_konst = 1;
+ }
+
+// initialize modification falgs
+ swap = 0;
+ q2_inc = 0;
+
+// decode jump and decide what modifications must be undertaken.
+ switch (c) {
+// equal ==, generate 'je'
+ case BEQ: break;
+// not equal !=, generate 'jne'
+ case BNE: break;
+// less than '<'
+ case BLT: break;
+// greater equal '>='
+ case BGE: break;
+// less equal '<='
+// This must be changed into BLT or BGE
+ case BLE:
+ if (q2_konst) {
+// Q2 is KONST, can't swap operands but must modify the constant
+ c = BLT;
+ q2_inc = 1;
+ } else {
+// must swap operands to map to available comparison instructions
+ c = BGE;
+ swap = 1;
+ }
+ break;
+// greater than '>'
+ case BGT:
+ if (q2_konst) {
+// Q2 is KONST, can't swap operands but must modify the constant
+ c = BGE;
+ q2_inc = 1;
+ } else {
+// must swap operands to map to available comparison instructions
+ c = BLT;
+ swap = 1;
+ }
+ break;
+ }
+
+/*
+MODIFY IC if neccessary.
+Modification looks like this:
+If q2_inc == 1, we increment KONST q2 by 1.
+If swap == 1, we swap operands.
+Either way, we replace the exisiting condition code with the new one.
+*/
+ if (swap) swap_operands(cmp);
+ if (q2_inc) {
+// partial constant
+ struct obj *x;
+// increment Q2
+ x = &cmp->q2;
+// not sure if this is the way I'm supposed to do this
+ eval_const(&x->val, q2typ(cmp));
+ gval.vmax = zmadd(vmax, 1);
+ eval_const(&gval, MAXINT);
+ insert_const(&x->val, q2typ(cmp));
+ }
+// insert new condition code
+ p->code = c;
+}
+
+//static void cg_branch
+
+static void cg_branch(FILE *f, struct IC *p)
+{
+ struct IC *cmp;
+ int c;
+// size in bytes
+ long size;
+ int typ;
+ char *sign;
+// jump target
+// The target in case the condition is satisfied
+ long target_true;
+// the target in case the condition is violated
+ long target_false;
+// partial constant
+ struct obj *x;
+
+
+ if (q1typ(p) != q2typ(p)) terror(0);
+
+ emit(f, "; compare\n");
+
+
+// try to find compare IC
+ cmp = p->prev;
+ while (cmp && cmp->code == FREEREG) cmp = cmp->prev;
+ if (!cmp || (cmp->code != COMPARE && cmp->code != TEST)) terror("-- cg_branch: compare not found");
+
+ typ = q1typ(cmp);
+ size = sizetab[typ&NQ];
+
+ if (!ISINT(typ)) terror("-- cg_branch: unexpected object type");
+
+// get jump target
+ target_true = (long)p->typf;
+ target_false = label_count++;
+
+ cg_branch_modify(cmp, p);
+
+// grab the branch instruction
+ c = p->code;
+
+// determine sign/unsigned modifier
+ sign = "s";
+ if (typ & UNSIGNED) {
+ sign = "u";
+ }
+
+// 1. step we allcoate necessay temporaries
+ track_ic(f, cmp);
+
+// We need to distinguish different operand sizes
+ if (size <= 2) {
+// First case takes care of CHAR and INT/SHORT
+ x = &cmp->q1;
+ emit_load(f, x->am->regval[0], x, typ, 0, "mov");
+// emit operation
+ if (x->am->regval[0]) {
+// operation is performed on temporaries
+ emit_load(f, x->am->regval[0], &cmp->q2, typ, 0, "cmp");
+ } else {
+// operation is performed directly on target (z == q1 for this to work)
+ emit_op(f, x, &cmp->q2, typ, 0, "cmp");
+ }
+// must restore temporaries here,
+ track_restore(f);
+
+ switch (c) {
+ case BLT:
+ emit(f, "\tj%sl\t%s%ld\n", sign, label_prefix, target_true);
+ break;
+ case BGE:
+ emit(f, "\tj%sge\t%s%ld\n", sign, label_prefix, target_true);
+ break;
+ case BEQ:
+ emit(f, "\tje\t%s%ld\n", label_prefix, target_true);
+ break;
+ case BNE:
+ emit(f, "\tjne\t%s%ld\n", label_prefix, target_true);
+ break;
+ }
+
+ } else if (size == 4) {
+// LONG
+ x = &cmp->q1;
+ emit_load(f, x->am->regval[0], x, typ, 0, "mov");
+ emit_load(f, x->am->regval[1], x, typ, 2, "mov");
+// emit operation
+ if (x->am->regval[1]) {
+// operation is performed on temporaries
+ emit_load(f, x->am->regval[1], &cmp->q2, typ, 2, "cmp");
+ } else {
+// operation is performed directly on target (z == q1 for this to work)
+ emit_op(f, x, &cmp->q2, typ, 2, "cmp");
+ }
+// must restore temporaries here,
+ track_restore2(f);// (but don't release)
+ switch (c) {
+ case BLT:
+ emit(f, "\tj%sl\t%s%ld\n", sign, label_prefix, target_true);
+ emit(f, "\tjne\t%sn%ld\n", label_prefix, target_false);
+ break;
+ case BGE:
+ emit(f, "\tj%sl\t%sn%ld\n", sign, label_prefix, target_false);
+ emit(f, "\tjne\t%s%ld\n", label_prefix, target_true);
+ break;
+ case BEQ:
+ emit(f, "\tjne\t%sn%ld\n", label_prefix, target_false);
+ break;
+ case BNE:
+ emit(f, "\tjne\t%sn%ld\n", label_prefix, target_true);
+ break;
+ }
+// here we have to reallocate temporary. HOWEVER if done cleverly we don't have
+// to reload it, I have to think about the whole thing a litte bit.
+ // (reload what is needed, use same temps as above)
+ emit_load(f, x->am->regval[0], x, typ, 0, "mov");
+
+ // emit operation
+ if (x->am->regval[0]) {
+// operation is performed on temporaries
+ emit_load(f, x->am->regval[0], &cmp->q2, typ, 0, "cmp");
+ } else {
+// operation is performed directly on target (z == q1 for this to work)
+ emit_op(f, x, &cmp->q2, typ, 0, "cmp");
+ }
+ track_restore(f);
+ switch (c) {
+ case BLT:
+ emit(f, "\tjuge\t%s%ld\n", label_prefix, target_true);
+ break;
+ case BGE:
+ emit(f, "\tjul\t%s%ld\n", label_prefix, target_true);
+ break;
+ case BEQ:
+ emit(f, "\tje\t%s%ld\n", label_prefix, target_true);
+ break;
+ case BNE:
+ emit(f, "\tjne\t%s%ld\n", label_prefix, target_true);
+ break;
+ }
+
+
+ } else {
+ terror("branch size not supported");
+ }
+
+// emit "not taken" label
+ emit(f, "%sn%ld:\n", label_prefix, target_false);
+
+// release temporaries
+ track_release();
+}
+
+static void cg_setreturn(FILE *f, struct IC *p)
+{
+ emit(f, "; set return\n");
+
+ if (sizetab[ztyp(p)&NQ] > regsize[p->z.reg]) terror("-- cg_setreturn: size mismatch");
+ emit_load(f, REG_R0, &p->q1, q1typ(p), 0, "mov");
+}
+
+static void cg_getreturn(FILE *f, struct IC *p)
+{
+ emit(f, "; get return\n");
+
+ if (p->q1.reg) {
+ emit_store(f, &p->z, p->q1.reg, ztyp(p), 0);
+ }
+}
+
+static void cg_movefromreg(FILE *f, struct IC *p)
+{
+ emit_store(f, &p->z, p->q1.reg, ztyp(p), 0);
+}
+
+static void cg_movetoreg(FILE *f, struct IC *p)
+{
+ emit_load(f, p->z.reg, &p->q1, ztyp(p), 0, "mov");
+}
+
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+int init_cg(void)
+{
+ int i;
+ int nregs;
+ int rtmp;
+ int rsave;
+
+/* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign = l2zm(2L);
+ char_bit = l2zm(8L);
+
+ sizetab[0] = 1; typname[0] = "strange"; align[0] = 1;
+ sizetab[CHAR] = 1; typname[CHAR] = "char"; align[CHAR] = 1;
+ sizetab[SHORT] = 2; typname[SHORT] = "short"; align[SHORT] = 2;
+ sizetab[INT] = 2; typname[INT] = "int"; align[INT] = 2;
+ sizetab[LONG] = 4; typname[LONG] = "long"; align[LONG] = 2;
+ sizetab[LLONG] = 8; typname[LLONG] = "long long"; align[LLONG] = 2;
+ sizetab[FLOAT] = 4; typname[FLOAT] = "float"; align[FLOAT] = 2;
+ sizetab[DOUBLE] = 8; typname[DOUBLE] = "double"; align[DOUBLE] = 2;
+ sizetab[LDOUBLE] = 8; typname[LDOUBLE] = "long double"; align[LDOUBLE] = 2;
+ sizetab[VOID] = 0; typname[VOID] = "void"; align[VOID] = 1;
+ sizetab[POINTER] = 2; typname[POINTER] = "pointer"; align[POINTER] = 2;
+ sizetab[ARRAY] = 0; typname[ARRAY] = "array"; align[ARRAY] = 1;
+ sizetab[STRUCT] = 0; typname[STRUCT] = "struct"; align[STRUCT] = 1;
+ sizetab[UNION] = 0; typname[UNION] = "union"; align[UNION] = 1;
+ sizetab[ENUM] = 2; typname[ENUM] = "enum"; align[ENUM] = 2;
+ sizetab[FUNKT] = 0; typname[FUNKT] = "function"; align[FUNKT] = 1;
+ sizetab[MAXINT] = 0;
+
+// fill in the default register description
+ regnames[0] = "noreg";
+ regnames[REG_R0] = "r0";
+ regnames[REG_R1] = "r1";
+ regnames[REG_R2] = "r2";
+ regnames[REG_R3] = "r3";
+ regnames[REG_R4] = "r4";
+ regnames[REG_R5] = "r5";
+ regnames[REG_R6] = "r6";
+ regnames[REG_R7] = "r7";
+ regnames[REG_R8] = "r8";
+ regnames[REG_R9] = "r9";
+ regnames[REG_R10] = "r10";
+ regnames[REG_R11] = "r11";
+ regnames[REG_R12] = "r12";
+ regnames[REG_R13] = "r13";
+
+ for (i = 1; i < MAXR+1; i++) {
+ regsize[i] = l2zm(2L);
+ regtype[i] = <yp;
+ regscratch[i] = 1;
+ regsa[i] = 0;
+ reg_prio[i] = 1;
+// private register tracking system
+// Indicate register is available as temporary.
+ track_status[i] = 0;
+ }
+
+// default numbers of registers to use
+ nregs = 6;
+// check command line flags for number of registers
+ if (g_flags[0] & USEDFLAG) {
+ nregs = g_flags_val[0].l;
+ }
+ if (nregs < 3) nregs = 3;
+ if (nregs > 14) nregs = 14;
+// limit available registers to 'nregs'
+ for (i = REG_R0+nregs; i <= REG_R13; i++) {
+ regsa[i] = 1;
+ regscratch[i] = 0;
+ track_status[i] |= TRACK_OFFLIMITS;
+ }
+
+// get the number of temporary registers to reserve
+ if (g_flags[2] & USEDFLAG) {
+ rtmp = g_flags_val[1].l;
+ } else {
+ rtmp = 0;
+ if (nregs >= 6) rtmp = 1;
+ if (nregs >= 9) rtmp = 2;
+ if (nregs >= 12) rtmp = 3;
+ }
+ if (rtmp < 0) rtmp = 0;
+ if (rtmp > 3) rtmp = 3;
+
+// remove temporary registers from code generator pool (on the top side)
+ for (i = nregs-rtmp; i < nregs; i++) {
+ regsa[REG_R0+i] = 1;
+ regscratch[REG_R0+i] = 0;
+// indicate to tracked that this is a dedicated temporary register
+ track_status[REG_R0+i] |= TRACK_DEDICATED;
+ }
+
+// get numbers of registers to save across function calls
+ if (g_flags[1] & USEDFLAG) {
+ rsave = g_flags_val[1].l;
+ } else {
+ rsave = 0;
+// automatically select
+ if (nregs >= 6) rsave = 2;
+ if (nregs >= 10) rsave = 4;
+ }
+ if (rsave < 0) rsave = 0;
+ if (rsave > nregs-rtmp) rsave = nregs-rtmp;
+
+ for (i = 0; i < rsave; i++) {
+ regscratch[REG_R0+nregs-rtmp-rsave+i] = 0;
+ }
+
+// SP is special
+ regnames[REG_SP] = "sp";
+ regscratch[REG_SP] = 0;
+ regsa[REG_SP] = 1;
+ track_status[REG_SP] |= TRACK_OFFLIMITS;
+// and FLAGS is special
+ regnames[REG_FLAGS] = "flags";
+ regscratch[REG_FLAGS] = 0;
+ regsa[REG_FLAGS] = 1;
+ track_status[REG_FLAGS] |= TRACK_OFFLIMITS;
+
+// print some status to the screen
+ printf("Falco16 CPU information\n");
+ printf(" GP registers: %d\n", nregs);
+ printf(" temporaries: %d\n", rtmp);
+ printf(" saves: %d\n", rsave);
+
+
+
+ /* Don't use multiple ccs. */
+ multiple_ccs = 0;
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=t_min(SHORT);
+ t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=t_max(SHORT);
+ t_max[LONG]=ul2zum(2147483647UL);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=t_max(UNSIGNED|SHORT);
+ tu_max[LONG]=ul2zum(4294967295UL);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+
+ target_macros=marray;
+
+// local label counter
+ label_count = 0;
+
+ return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+/* A pointer MUST be returned in a register. The code-generator */
+/* has to simulate a pseudo register if necessary. */
+{
+ int ret;
+ int p;
+
+ ret = 0;
+ p = t->flags & NQ;
+
+ if (sizetab[p] <= regsize[REG_R0]) ret = REG_R0;
+
+ return ret;
+}
+
+int reg_pair(int r, struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ return 0;
+}
+
+
+int regok(int r, int t, int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+// simple paramtere check
+ if(r == 0) return 0;
+
+// if floating point, we don't keep them in registers at all
+ if (ISFLOAT(t)) return 0;
+
+// Must be integer or pointer, keep them in register if possible.
+ t &= NQ;
+ if (sizetab[t] <= regsize[r]) return 1;
+
+ return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+
+ return 0;
+}
+
+int must_convert(int src, int dst, int const_expr)
+{
+ int srcp = src & NQ;
+ int dstp = dst & NQ;
+
+ if (ISINT(src) && ISINT(dst)) {
+ if (sizetab[srcp] >= sizetab[dstp]) return 0;
+ // if (sizetab[srcp] == 1 && sizetab[dstp] == 2) return 0;
+ } else if (ISINT(src) && ISPOINTER(dst)) {
+ if (sizetab[srcp] >= sizetab[dstp]) return 0;
+ // if (sizetab[srcp] == 1 && sizetab[dstp] == 2) return 0;
+ } else if (ISPOINTER(src) && ISINT(dst)) {
+ if (sizetab[srcp] >= sizetab[dstp]) return 0;
+ // if (sizetab[srcp] == 1 && sizetab[dstp] == 2) return 0;
+ }
+
+// no conversion when src and dst are same type
+ if (src == dst) return 0;
+
+
+ return 1;
+}
+
+/* Return name of library function, if this node should be
+ implemented via libcall. */
+char *use_libcall(np p)
+{
+
+/*
+ following operations go into library
+
+N - native
+L - library call (some paramters are implemented native)
+A - library call (all the time)
+X - not supported
+- - not valid (not generated by front-end)
+? - what to do?
+
+ CHAR SHORT/INT LONG LLONG FLOAT DOUBLE LDOUBLE
+
+CMP N N N X ? X X
+OR N N N X - - -
+XOR N N N X - - -
+AND N N N X - - -
+LSHIFT L L L X - - -
+RSHIFT L L L X - - -
+ADD N N N X A X X
+SUB N N N X A X X
+MULT L L L X A X X
+DIV L L L X A X X
+MOD L L L X A X X
+*/
+
+ static char fname[16];
+ char *ret;
+ int f;
+ char *sign;
+ char *dtype;
+ int code;
+
+ if(p->flags>=EQUAL&&p->flags<=GREATEREQ){
+ extern struct Typ *arith_typ();
+ struct Typ *t=arith_typ(p->left->ntyp,p->right->ntyp);
+ f=t->flags&NU;
+ freetyp(t);
+ if((f&NQ)==LLONG){
+ sprintf(fname,"__cmp%s%sll",ename[p->flags],(f&UNSIGNED)&&p->flags!=EQUAL&&p->flags!=INEQUAL?"u":"");
+ ret=fname;
+ }else if((f&NQ)==FLOAT){
+ sprintf(fname,"__cmp%s%sf",ename[p->flags],(f&UNSIGNED)&&p->flags!=EQUAL&&p->flags!=INEQUAL?"u":"");
+ ret=fname;
+ }else if((f&NQ)==DOUBLE||(f&NQ)==LDOUBLE){
+ sprintf(fname,"__cmp%s%sd",ename[p->flags],(f&UNSIGNED)&&p->flags!=EQUAL&&p->flags!=INEQUAL?"u":"");
+ ret=fname;
+ }
+ }else{
+// get code of operation
+ code = p->flags;
+// get data type
+ f = p->ntyp->flags & NU;
+
+ sign = "s";
+ if (f & UNSIGNED) {
+ sign = "u";
+ }
+
+ switch (f & NQ) {
+ case CHAR: dtype = "i8"; break;
+ case SHORT:
+ case INT: dtype = "i16"; break;
+ case LONG: dtype = "i32"; break;
+ case FLOAT: dtype = "f32"; break;
+ case DOUBLE: dtype = "f64"; break;
+ default: dtype = ""; break;
+ terror("--use_libcall: data type not supported");
+ break;
+ }
+// default is no function
+ ret = 0;
+ switch (code) {
+ case LSHIFT: sprintf(fname, "__shl_%s%s", sign, dtype); ret = fname; break;
+ case RSHIFT: sprintf(fname, "__shr_%s%s", sign, dtype); ret = fname; break;
+ case ADD:
+ if (ISFLOAT(f)) { sprintf(fname, "__add_%s", dtype); ret = fname; }
+ break;
+ case SUB:
+ if (ISFLOAT(f)) { sprintf(fname, "__sub_%s", dtype); ret = fname; }
+ break;
+ case MINUS:
+ if (ISFLOAT(f)) { sprintf(fname, "__neg_%s", dtype); ret = fname; }
+ break;
+ case MULT: sprintf(fname, "__mul_%s%s", sign, dtype); ret = fname; break;
+ case DIV:
+ sprintf(fname, "__div_%s%s", sign, dtype); ret = fname;
+ break;
+ case MOD:
+ sprintf(fname, "__mod_%s%s", sign, dtype); ret = fname;
+ break;
+ }
+ }
+
+ if(ret){
+/* declare function if necessary */
+ struct struct_declaration *sd;struct Typ *t;
+ if(!find_ext_var(ret)){
+ sd = mymalloc(sizeof(*sd));
+ sd->count = 0;
+ t = new_typ();
+ t->flags = FUNKT;
+ t->exact = add_sd(sd, FUNKT);
+ t->next = clone_typ(p->ntyp);
+ add_var(ret, t, EXTERN, 0);
+ }
+ }
+ return ret;
+}
+
+
+
+void gen_ds(FILE *f, zmax size, struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ if (newobj) {
+ emit(f, "\tdb\tdup(%ld, 0)\n", zm2l(size));
+ } else {
+ emit (f, "-- somehting's wrong\n");
+ }
+ newobj = 0;
+}
+
+void gen_align(FILE *f, zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ int p;
+ p = p;
+}
+
+void gen_var_head(FILE *f, struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;
+
+ if (v->clist) constflag = is_const(v->vtyp);
+ if (v->storage_class == STATIC) {
+ if ((v->vtyp->flags&NQ) == FUNKT) return;
+ if (v->clist && (!constflag) && section != SEC_DATA) {
+ emit(f, "\n\tsection\t%s\n", sec_dataname);
+ if (f) section = SEC_DATA;
+ }
+ if (v->clist && constflag && section != SEC_RODATA) {
+ emit(f, "\n\tsection\t%s\n", sec_rodataname);
+ if (f) section = SEC_RODATA;
+ }
+ if (!v->clist && section != SEC_BSS) {
+ emit(f, "\n\tsection\t%s\n", sec_bssname);
+ if (f) section = SEC_BSS;
+ }
+ emit(f, "%s%ld:", label_prefix, zm2l(v->offset));
+
+ newobj = 1;
+ }
+ if (v->storage_class == EXTERN) {
+ if (v->flags & (DEFINED|TENTATIVE)) {
+ if (v->clist && (!constflag) && section != SEC_DATA) {
+ emit(f, "\n\tsection\t%s\n", sec_dataname);
+ if (f) section=SEC_DATA;
+ }
+ if (v->clist && constflag && section != SEC_RODATA) {
+ emit(f, "\n\tsection\t%s\n", sec_rodataname);
+ if(f) section = SEC_RODATA;
+ }
+ if (!v->clist && section != SEC_BSS) {
+ emit(f, "\n\tsection\t%s\n", sec_bssname);
+ if (f) section = SEC_BSS;
+ }
+ emit(f, "\tpublic\t%s%s\n", ident_prefix, v->identifier);
+ emit(f, "%s%s:", ident_prefix, v->identifier);
+ newobj = 1;
+ }
+ }
+}
+
+void gen_dc(FILE *f, int t, struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ emit(f, "\t%s\t", dct[t&NQ]);
+ if (!p->tree) {
+ if ((t&NQ) == FLOAT || (t&NQ) == DOUBLE) {
+ emit(f, "-- floating point not supported\n");
+ } else {
+ emitval(f, &p->val, t&NU);
+ }
+ } else {
+ emit(f, "-- gen_dc: what the hell\n");
+ }
+ emit(f, "\n");
+ newobj = 0;
+}
+
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE *f, struct IC *p, struct Var *v, zmax offset)
+/* The main code-generation. */
+{
+ struct IC *head;
+ int c;
+
+ if (DEBUG&1) printf("gen_code()\n");
+
+ loff = ((zm2l(offset) + 1) / 2) * 2;
+ stackoffset = 0;
+ cd_function_entry(f, v, loff);
+
+// initialize temporary register tracking
+ track_init();
+
+ head = p;
+ for(; p; p = p->next){
+// print: this doesn't work right, due to emit buffer
+ printic(f, p);
+ emit(f, "; stackoffset: %d\n", stackoffset);
+
+// get operation code
+ c = p->code;
+
+ switch (c) {
+ case NOP:
+ break;
+
+ case ASSIGN:
+ case CONVERT:
+ cg_assign(f, p);
+ break;
+
+ case LSHIFT:
+ cg_lshift(f, p);
+ break;
+ case RSHIFT:
+ cg_rshift(f, p);
+ break;
+
+ case ADD:
+ case ADDI2P:
+ case SUB:
+ case SUBIFP:
+ case OR:
+ case XOR:
+ case AND:
+ cg_alu(f, p);
+ break;
+
+ case MULT:
+ cg_mult(f, p);
+ break;
+
+ case DIV:
+ cg_div(f, p);
+ break;
+
+ case MOD:
+ cg_mod(f, p);
+ break;
+
+ case KOMPLEMENT:
+ cg_komplement(f, p);
+ break;
+
+ case MINUS:
+ cg_minus(f, p);
+ break;
+
+ case ADDRESS:
+ cg_address(f, p);
+ break;
+
+ case TEST:
+// change TEST into COMPARE
+ cg_test(f, p);
+ break;
+
+ case COMPARE:
+// This is handled by the branch IC. Nothing to do here.
+ break;
+
+ case LABEL:
+// must restore all temporaries before any label
+// This is not good, as vbcc seems to be generating more labels than necessaty,
+// pretty much defeating our clever system. We must do some more processing here.
+ track_restore(f);
+ emit(f, "%s%ld:\n", label_prefix, (long)p->typf);
+ break;
+
+ case BEQ:
+ case BNE:
+ case BLT:
+ case BGE:
+ case BLE:
+ case BGT:
+ cg_branch(f, p);
+ break;
+ case BRA:
+// restore temporaries
+ track_restore(f);
+ emit(f, "\tjmp\t%s%ld\n", label_prefix, (long)p->typf);
+ break;
+
+ case PUSH:
+ cg_push(f, p);
+ break;
+
+ case CALL:
+ cg_call(f, p);
+ break;
+
+ case SETRETURN:
+ cg_setreturn(f, p);
+ break;
+
+ case GETRETURN:
+ cg_getreturn(f, p);
+ break;
+
+ case ALLOCREG:
+// register is being used, indicate it can only be used if saved
+ track_status[p->q1.reg] |= TRACK_ALLOCREG;
+ break;
+
+ case FREEREG:
+// register is again free
+ track_status[p->q1.reg] &= ~(TRACK_ALLOCREG);
+ break;
+
+ case MOVEFROMREG:
+ cg_movefromreg(f, p);
+ break;
+
+ case MOVETOREG:
+ cg_movetoreg(f, p);
+ break;
+
+
+ default:
+ emit(f, "unhandled IC\n");
+ }
+ emit(f, "\n");
+ }
+ cg_function_exit(f, v, loff);
+
+}
+
+int shortcut(int code, int typ)
+{
+ if (sizetab[typ&NQ] > 2) return 0;
+ return 1;
+}
+
+
+void cleanup_cg(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+
+}
diff --git a/machines/falco16/machine.dt b/machines/falco16/machine.dt
new file mode 100755
index 0000000..eab38c9
--- /dev/null
+++ b/machines/falco16/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S16BULE S16BUBE
+
+
diff --git a/machines/falco16/machine.h b/machines/falco16/machine.h
new file mode 100755
index 0000000..bdebc42
--- /dev/null
+++ b/machines/falco16/machine.h
@@ -0,0 +1,142 @@
+/*
+ FALCO16 v3
+*/
+
+/*#include "supp.h"*/
+#include "dt.h"
+
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+struct AddressingMode {
+// register to be used as temporary pointer
+ int regptr;
+// register to be used as temporary value
+// We support long and float and therfore need potentially 2 registers
+ int regval[2];
+};
+
+/* The number of registers of the target machine. */
+#define MAXR 16
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 3
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P INT
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 0
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 1
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 4
+
+/* Parameter push order */
+#undef ORDERED_PUSH
+
+/* Parameters are sometimes passed in registers without __reg. */
+//#define HAVE_REGPARMS 1
+#undef HAVE_REGPARMS
+
+/* use library calls for some basic ICs */
+#define HAVE_LIBCALLS 1
+
+/* Structure for reg_parm(). */
+struct reg_handle{
+ unsigned long gregs;
+ unsigned long fregs;
+};
+
+
+/* we do not need register-pairs */
+#undef HAVE_REGPAIRS
+
+/* select size_t. unsigned int or unsigned long, the default */
+#undef HAVE_INT_SIZET
+
+/* size of buffer for asm-output, this can be used to do
+ peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 1
+
+/* We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+
+/* We have some target-specific variable attributes. */
+#undef HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#undef HAVE_TARGET_PRAGMAS
+
+/* We keep track of all registers modified by a function. */
+#undef HAVE_REGS_MODIFIED
+
+/* We have a implement our own cost-functions to adapt
+ register-allocation */
+#undef HAVE_TARGET_RALLOC
+
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+ optimizations on code which can already be implemented by efficient
+ assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we do need extra elements in the IC */
+#define HAVE_EXT_IC 1
+struct Regtmp {
+// register number
+ int reg;
+// must be saved before used?
+ int save;
+};
+#define MAX_TMPREG 3
+struct ext_ic {
+// temporary ptr register to use with this IC
+ struct Regtmp reg_tmp[MAX_TMPREG];
+};
+
+/* We have extended types! What we have to do to support them: */
+/* - #define HAVE_EXT_TYPES
+ - #undef all standard types
+ - #define all standard types plus new types
+ - write eval_const and insert_const
+ - write typedefs for zmax and zumax
+ - define atyps union
+ - write typname[]
+ - write conv_typ()
+ - optionally #define ISPOINTER, ISARITH, ISINT etc.
+ - optionally #define HAVE_TGT_PRINTVAL and write printval
+ - optionally #define POINTER_TYPE
+ - optionally #define HAVE_TGT_FALIGN and write falign
+ - optionally #define HAVE_TGT_SZOF and write szof
+ - optionally add functions for attribute-handling
+*/
+#undef HAVE_TGT_PRINTVAL
+#undef HAVE_EXT_TYPES
+
+
+
diff --git a/machines/fire16/machine.c b/machines/fire16/machine.c
new file mode 100644
index 0000000..e838c11
--- /dev/null
+++ b/machines/fire16/machine.c
@@ -0,0 +1,2280 @@
+/*
+ * Backend for the Fire16 iCE40 SoftCore
+ * (c) 2019 by Sylvain Munaut
+ */
+
+#define DBG
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for fire16 v0.1 (c) 2019 by Sylvain Munaut";
+
+/* Commandline-flags the code-generator accepts */
+char *g_flags_name[MAXGF]={"tiny-dmem", "tiny-pmem"};
+int g_flags[MAXGF]={0, 0};
+union ppi g_flags_val[MAXGF];
+
+/* Extended type names */
+char *typname[]={"n/a", "char","short","int","long","long long",
+ "float","double","long double","void",
+ "dmem-pointer","pmem-pointer",
+ "array","struct","union","enum","function"};
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. will be initialized in init_cg(),
+ register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+ estimated cost-saving can be obtained by several registers, the
+ one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={0};
+
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1] = {0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1] = {0,1,1,1,2,4,2,4,4,1,1,1,1,1,1,1,1,1,1};
+
+/* Macros */
+static char *marray[] = {
+ "__pmem=__attr(\"pmem\")",
+ 0
+};
+
+/* Register types */
+struct Typ ityp={SHORT}, ltyp={LONG};
+
+/* Registers num */
+enum {
+ R_NONE = 0,
+ R_R0, R_R1, R_R2, R_R3, R_R4, R_R5, R_R6, R_R7,
+ R_R8, R_R9, R_RA, R_RB, R_RC, R_RD, R_RE, R_RF,
+ R_S0, R_S1, R_S2, R_S3, R_S4, R_S5, R_S6, R_S7,
+ R_S8, R_S9, R_SA, R_SB, R_SC, R_SD, R_SE, R_SF,
+ R_R0P, R_R2P, R_R4P, R_R6P, R_R8_P, R_RAP, R_RCP, R_REP,
+ R_S0P, R_S2P, R_S4P, R_S6P, R_S8_P, R_SAP, R_SCP, R_SEP,
+ R_A, R_X, R_Y, R_I
+};
+
+#define isgpr(r) ((r) >= R_R0 && (r) <= R_SEP)
+
+/* Identifier prefixes */
+static const char *idprefix="_", *labprefix="l";
+
+#define isreg(x) (((x)->flags&(REG|DREFOBJ))==REG)
+#define isconst(x) (((x)->flags&(KONST|DREFOBJ))==KONST)
+
+#define ISTSHORT(t) (((t)&NQ)==CHAR || ((t)&NQ)==SHORT || ((t)&NQ)==INT || ((t)&NQ)==DPOINTER || ((t)&NQ)==PPOINTER)
+#define ISTLONG(t) (((t)&NQ)==LONG || ((t)&NQ)==FLOAT)
+
+#define STR_PMEM "pmem"
+
+#define TINY_DMEM (g_flags[0] & USEDFLAG)
+#define TINY_PMEM (g_flags[1] & USEDFLAG)
+#define TINY_IMM(i) ( (((i) & 0xff00) == 0xff00) || (((i) & 0xff00) == 0x0000) )
+
+static char *sym_name(struct Var *var)
+{
+ static char sym[128]; /* fixme ? */
+
+ if (isstatic(var->storage_class))
+ snprintf(sym, sizeof(sym)-1, "%s%ld", labprefix, zm2l(var->offset));
+ else
+ snprintf(sym, sizeof(sym)-1, "%s%s", idprefix, var->identifier);
+
+ return sym;
+}
+
+static long const2long(struct obj *o, int dtyp)
+{
+ if (!(o->flags & KONST))
+ ierror(0);
+ eval_const(&o->val, dtyp);
+ return zm2l(vmax);
+}
+
+struct gc_state
+{
+ FILE *f;
+
+ int reg_busy[MAXR+1]; /* Track used registers */
+
+ int op_save; /* Saved register to restore before op end */
+ long val_rv; /* Return Value immediate (must be small enough) */
+ int reg_rv; /* Return Value register, 0=none */
+ int reg_lw; /* Register written in the last emitted op code */
+
+ int s_argsize;
+ int s_localsize;
+ int s_savesize;
+
+ int cmp_signed; /* Last comparison was signed */
+ int cmp_cur_z; /* Current state of z flag */
+};
+
+static int
+_gc_find_reg(struct gc_state *gc, int pair)
+{
+ int min, max, r;
+
+ min = pair ? R_R0P : R_R0;
+ max = pair ? R_SEP : R_SF;
+
+ /* Try for a scratch reg first */
+ for (r=min; r<=max; r++)
+ if (!gc->reg_busy[r] && !regsa[r] && regscratch[r])
+ return r;
+
+ /* Ok ... anything will do */
+ for (r=min; r<=max; r++)
+ if (!gc->reg_busy[r] && !regsa[r])
+ return r;
+
+ /* Nothing :/ */
+ return 0;
+}
+
+
+/* Stack layout: (grows toward 0)
+ *
+ * ,------------------------------------------------,
+ * Y | (next available word) | <- Y pointer
+ * | arguments to called functions [size=s_argsize] |
+ * | local variables [size=s_localsize] |
+ * | saved register [size=s_savesize] |
+ * | return-address save [size=1] |
+ * Y+N | arguments to this function [size=?] |
+ * `------------------------------------------------'
+ */
+static long
+_gc_real_offset(struct gc_state *gc, struct Var *v, long add_offset)
+{
+ long off = zm2l(v->offset);
+
+ if (off < 0) {
+ /* function parameter */
+ off = gc->s_localsize + gc->s_savesize + 1 - (off + zm2l(maxalign));
+ }
+
+ off += gc->s_argsize;
+ off += add_offset;
+ off += 1; /* Because we point to the next available word */
+
+ return off;
+}
+
+#define _gc_emit(gc, ...) do { \
+ (gc)->reg_lw = 0; \
+ emit((gc)->f, __VA_ARGS__ ); \
+} while (0)
+
+static void
+_gc_emit_nop(struct gc_state *gc)
+{
+ gc->reg_lw = 0;
+ gc->cmp_cur_z = 0;
+ emit(gc->f, "\tnop\n" );
+}
+
+/* Emit a IMM opcode prefix if the constant requires it */
+static long
+_gc_emit_imm(struct gc_state *gc, long v)
+{
+ v = v & 0xffff;
+
+ if ((v & 0xff00) == 0) {
+ return v;
+ } else if ((v & 0xff00) == 0xff00) {
+ return - ((v ^ 0xffff) + 1);
+ } else {
+ gc->reg_lw = 0;
+ emit(gc->f, "\timm\t$%d\n", (v >> 8) & 0xff);
+ return v & 0xff;
+ }
+}
+
+/* Emit movs between any register pairs and any single GPR & A */
+static void
+_gc_emit_mov(struct gc_state *gc, int dst, int src)
+{
+ if (src == dst)
+ return;
+
+ if ((src == gc->reg_lw) && isgpr(src))
+ emit(gc->f, "\tnop\n");
+
+ emit(gc->f, "\tmov\t%s, %s\n", regnames[dst], regnames[src]);
+
+ BSET(regs_modified, dst);
+
+ gc->reg_lw = isgpr(dst) ? dst : 0;
+}
+
+/* Emit opcode and checks for depencies */
+static void
+_gc_emit_alu(struct gc_state *gc, const char *opcode,
+ int dst, int src1, int src2, long imm)
+{
+ int dep1 = (src1 == gc->reg_lw) && isgpr(src1);
+ int dep2 = (src2 == gc->reg_lw) && isgpr(src2);
+ char dst_str[16], *op1_str, op2_str[16], imm_str[16];
+
+ if ((dep1 || dep2) && (src1 != R_I) && (src2 != R_I))
+ emit(gc->f, "\tnop\n");
+
+ if ((src1 == R_I) || (src2 == R_I)) {
+ imm = _gc_emit_imm(gc, imm);
+ if ((dst && (dst != R_A)) ||
+ ((src1 != R_I) && (src1 != R_A)) ||
+ ((src2 != R_I) && (src2 != R_A))) {
+ emit(gc->f, "\timm\t$%d\n", imm);
+ snprintf(imm_str, sizeof(imm_str)-1, "%s", regnames[R_I]);
+ } else {
+ snprintf(imm_str, sizeof(imm_str)-1, "$%ld", imm);
+ }
+ }
+
+ dst_str[0] = op2_str[0] = 0;
+ op1_str = (src1 != R_I) ? regnames[src1] : imm_str;
+ if (dst) snprintf(dst_str, sizeof(dst_str)-1, "%s, ", regnames[dst]);
+ if (src2) snprintf(op2_str, sizeof(op2_str)-1, ", %s", (src2 != R_I) ? regnames[src2] : imm_str);
+
+ emit(gc->f, "\t%s\t%s%s%s\n", opcode, dst_str, op1_str, op2_str);
+
+ BSET(regs_modified, dst);
+
+ gc->reg_lw = isgpr(dst) ? dst : 0;
+ gc->cmp_cur_z = gc->reg_lw;
+}
+
+static void
+_gc_move_gpr(struct gc_state *gc, int dst, int src)
+{
+ struct rpair rp_src, rp_dst;
+ int ip_src, ip_dst;
+
+ if (src == dst)
+ return;
+
+ ip_dst = reg_pair(dst, &rp_dst);
+ ip_src = reg_pair(src, &rp_src);
+ if ((regsize[dst] != regsize[src]) || (ip_dst != ip_src))
+ ierror(0); /* Shouldn't happen */
+
+ if (ip_dst) {
+ if (gc->reg_lw == rp_src.r1) {
+ _gc_emit_mov(gc, R_A, rp_src.r2);
+ _gc_emit_mov(gc, rp_dst.r2, R_A);
+ _gc_emit_mov(gc, R_A, rp_src.r1);
+ _gc_emit_mov(gc, rp_dst.r1, R_A);
+ } else {
+ _gc_emit_mov(gc, R_A, rp_src.r1);
+ _gc_emit_mov(gc, rp_dst.r1, R_A);
+ _gc_emit_mov(gc, R_A, rp_src.r2);
+ _gc_emit_mov(gc, rp_dst.r2, R_A);
+ }
+ } else {
+ /* _gc_emit_mov will handle if src or dst is R_A */
+ _gc_emit_mov(gc, R_A, src);
+ _gc_emit_mov(gc, dst, R_A);
+ }
+}
+
+static void
+_gc_store_to_mem(struct gc_state *gc, int val_reg, int dtyp,
+ long ptr_const, int ptr_reg, struct Var *var)
+{
+ struct rpair rp;
+ char *opcode;
+ int tiny;
+ int is_pair;
+
+ if (dtyp == DPOINTER) {
+ opcode = "std";
+ tiny = TINY_DMEM;
+ } else if (dtyp == PPOINTER) {
+ opcode = "stp";
+ tiny = TINY_PMEM;
+ } else {
+ ierror(0);
+ }
+
+ is_pair = reg_pair(val_reg, &rp);
+
+ if (var)
+ {
+ /* Variable */
+ if (isauto(var->storage_class)) {
+ /* Stack variable always in data mem */
+ if (dtyp != DPOINTER)
+ ierror(1);
+
+ long sp_offset = _gc_real_offset(gc, var, ptr_const);
+
+ if (sp_offset <= 15) {
+ /* Offset is small enough for indexed Y access */
+ if (is_pair) {
+ /* 32 bit */
+ _gc_emit_mov(gc, R_A, rp.r1);
+ _gc_emit(gc, "\t%s\tA, [Y++, $%d]\n", opcode, sp_offset);
+ _gc_emit_mov(gc, R_A, rp.r2);
+ _gc_emit(gc, "\t%s\tA, [Y--, $%d]\n", opcode, sp_offset);
+ } else {
+ /* 16 bit */
+ _gc_emit_mov(gc, R_A, val_reg);
+ _gc_emit(gc, "\t%s\tA, [Y, $%d]\n", opcode, sp_offset);
+ }
+ } else {
+ /* Offset is too large ... load address in A and fall back to code below */
+ _gc_emit(gc, "\tmov\tA, Y\n");
+ _gc_emit(gc, "\tadd A, A, $%d\n", sp_offset);
+ ptr_reg = R_A;
+ }
+ } else if (isextern(var->storage_class) || isstatic(var->storage_class)) {
+ /* Symbol name */
+ char *sym = sym_name(var);
+
+ /* Make access using absolute immediate addressing */
+ if (reg_pair(val_reg, &rp)) {
+ /* 32 bit */
+ _gc_emit_mov(gc, R_A, rp.r1);
+ if (!tiny) _gc_emit(gc, "\timm\t$(hi(%s+%d))\n", sym, ptr_const);
+ _gc_emit(gc, "\t%s\tA, [$(lo(%s+%d))]\n", opcode, sym, ptr_const);
+ _gc_emit_mov(gc, R_A, rp.r2);
+ if (!tiny) _gc_emit(gc, "\timm\t$(hi(%s+%d))\n", sym, ptr_const+1);
+ _gc_emit(gc, "\t%s\tA, [$(lo(%s+%d))]\n", opcode, sym, ptr_const+1);
+ } else {
+ /* 16 bit */
+ _gc_emit_mov(gc, R_A, val_reg);
+ if (!tiny) _gc_emit(gc, "\timm\t$(hi(%s+%d))\n", sym, ptr_const);
+ _gc_emit(gc, "\t%s\tA, [$(lo(%s+%d))]\n", opcode, sym, ptr_const);
+ }
+ } else {
+ ierror(0);
+ }
+ }
+
+ if (ptr_reg)
+ {
+ /* Register pointer */
+ _gc_emit_mov(gc, R_A, ptr_reg);
+ _gc_emit_mov(gc, R_X, R_A);
+
+ if (is_pair) {
+ /* 32 bit */
+ _gc_emit_mov(gc, R_A, rp.r1);
+ _gc_emit(gc, "\t%s\tA, [X++]\n", opcode);
+ _gc_emit_mov(gc, R_A, rp.r2);
+ _gc_emit(gc, "\t%s\tA, [X--]\n", opcode);
+ } else {
+ /* 16 bit */
+ _gc_emit_mov(gc, R_A, val_reg);
+ _gc_emit(gc, "\t%s\tA, [X]\n", opcode);
+ }
+ }
+
+ if (!ptr_reg && !var)
+ {
+ /* Constant immediate pointer */
+ if (is_pair) {
+ /* 32 bit access */
+ _gc_emit_mov(gc, R_A, rp.r1);
+ _gc_emit(gc, "\t%s\tA, [$%d]\n", opcode,
+ tiny ? (ptr_const+0) : _gc_emit_imm(gc, ptr_const+0));
+ _gc_emit_mov(gc, R_A, rp.r2);
+ _gc_emit(gc, "\t%s\tA, [$%d]\n", opcode,
+ tiny ? (ptr_const+1) : _gc_emit_imm(gc, ptr_const+1));
+ } else {
+ /* 16 bit access */
+ _gc_emit_mov(gc, R_A, val_reg);
+ _gc_emit(gc, "\t%s\tA, [$%d]\n", opcode,
+ tiny ? ptr_const : _gc_emit_imm(gc, ptr_const));
+ }
+ }
+}
+
+static void
+_gc_load_from_mem(struct gc_state *gc, int val_reg, int dtyp,
+ long ptr_const, int ptr_reg, struct Var *var)
+{
+ struct rpair rp;
+ char *opcode;
+ int tiny;
+ int is_pair;
+
+ if (dtyp == DPOINTER) {
+ opcode = "ldd";
+ tiny = TINY_DMEM;
+ } else if (dtyp == PPOINTER) {
+ opcode = "ldp";
+ tiny = TINY_PMEM;
+ } else {
+ ierror(0);
+ }
+
+ is_pair = reg_pair(val_reg, &rp);
+
+ if (var)
+ {
+ /* Variable */
+ if (isauto(var->storage_class)) {
+ /* Stack variable always in data mem */
+ if (dtyp != DPOINTER)
+ ierror(1);
+
+ long sp_offset = _gc_real_offset(gc, var, ptr_const);
+
+ if (sp_offset <= 15) {
+ /* Offset is small enough for indexed Y access */
+ if (is_pair) {
+ /* 32 bit */
+ _gc_emit(gc, "\t%s\tA, [Y++, $%d]\n", opcode, sp_offset);
+ _gc_emit_mov(gc, rp.r1, R_A);
+ _gc_emit(gc, "\t%s\tA, [Y--, $%d]\n", opcode, sp_offset);
+ _gc_emit_mov(gc, rp.r2, R_A);
+ } else {
+ /* 16 bit */
+ _gc_emit(gc, "\t%s\tA, [Y, $%d]\n", opcode, sp_offset);
+ _gc_emit_mov(gc, val_reg, R_A);
+ }
+ } else {
+ /* Offset is too large ... load address in A and fall back to code below */
+ _gc_emit(gc, "\tmov\tA, Y\n");
+ _gc_emit(gc, "\tadd A, A, $%d\n", sp_offset);
+ ptr_reg = R_A;
+ }
+ } else if (isextern(var->storage_class) || isstatic(var->storage_class)) {
+ /* Symbol name */
+ char *sym = sym_name(var);
+
+ /* Make access using absolute immediate addressing */
+ if (is_pair) {
+ /* 32 bit */
+ if (!tiny) _gc_emit(gc, "\timm\t$(hi(%s+%d))\n", sym, ptr_const);
+ _gc_emit(gc, "\t%s\tA, [$(lo(%s+%d))]\n", opcode, sym, ptr_const);
+ if (dtyp == PPOINTER) _gc_emit_nop(gc);
+ _gc_emit_mov(gc, rp.r1, R_A);
+ if (!tiny) _gc_emit(gc, "\timm\t$(hi(%s+%d))\n", sym, ptr_const+1);
+ _gc_emit(gc, "\t%s\tA, [$(lo(%s+%d))]\n", opcode, sym, ptr_const+1);
+ if (dtyp == PPOINTER) _gc_emit_nop(gc);
+ _gc_emit_mov(gc, rp.r2, R_A);
+ } else {
+ /* 16 bit */
+ if (!tiny) _gc_emit(gc, "\timm\t$(hi(%s+%d))\n", sym, ptr_const);
+ _gc_emit(gc, "\t%s\tA, [$(lo(%s+%d))]\n", opcode, sym, ptr_const);
+ if (dtyp == PPOINTER) _gc_emit_nop(gc);
+ _gc_emit_mov(gc, val_reg, R_A);
+ }
+ } else {
+ ierror(0);
+ }
+ }
+
+ if (ptr_reg)
+ {
+ /* Register pointer */
+ _gc_emit_mov(gc, R_A, ptr_reg);
+ _gc_emit_mov(gc, R_X, R_A);
+
+ if (is_pair) {
+ /* 32 bit access */
+ _gc_emit(gc, "\t%s\tA, [X++]\n", opcode);
+ if (dtyp == PPOINTER) _gc_emit_nop(gc);
+ _gc_emit_mov(gc, rp.r1, R_A);
+ _gc_emit(gc, "\t%s\tA, [X--]\n", opcode);
+ if (dtyp == PPOINTER) _gc_emit_nop(gc);
+ _gc_emit_mov(gc, rp.r2, R_A);
+ } else {
+ /* 16 bit access */
+ _gc_emit(gc, "\t%s\tA, [X]\n", opcode);
+ if (dtyp == PPOINTER) _gc_emit_nop(gc);
+ _gc_emit_mov(gc, val_reg, R_A);
+ }
+ }
+
+ if (!ptr_reg && !var)
+ {
+ /* Constant immediate pointer */
+ if (is_pair) {
+ /* 32 bit access */
+ _gc_emit(gc, "\t%s\tA, [$%d]\n", opcode,
+ tiny ? (ptr_const+0) : _gc_emit_imm(gc, ptr_const+0));
+ if (dtyp == PPOINTER) _gc_emit_nop(gc);
+ _gc_emit_mov(gc, rp.r1, R_A);
+ _gc_emit(gc, "\t%s\tA, [$%d]\n", opcode,
+ tiny ? (ptr_const+1) : _gc_emit_imm(gc, ptr_const+1));
+ if (dtyp == PPOINTER) _gc_emit_nop(gc);
+ _gc_emit_mov(gc,rp.r2, R_A);
+ } else {
+ /* 16 bit access */
+ _gc_emit(gc, "\t%s\tA, [$%d]\n", opcode,
+ tiny ? ptr_const : _gc_emit_imm(gc, ptr_const));
+ if (dtyp == PPOINTER) _gc_emit_nop(gc);
+ _gc_emit_mov(gc, val_reg, R_A);
+ }
+ }
+}
+
+/* Selects a register for the result to be computed in */
+static int
+_gc_store_sel(struct IC *p)
+{
+ int t;
+
+ /* Register destination ? */
+ if (isreg(&p->z))
+ return p->z.reg;
+
+ /* If not, use the scratch registers as temporaries */
+ /* (ideally we should find some free scratch ones and use that
+ * instead of having 'reserved' ones ...) */
+ t = ztyp(p) & NQ;
+ if (ISSCALAR(t) && (msizetab[t] == 1))
+ return R_RF;
+ if (ISSCALAR(t) && (msizetab[t] == 2))
+ return R_REP;
+
+ /* Couldn't find a fit ? */
+ ierror(0);
+}
+
+static void
+_gc_op_pre(struct gc_state *gc, struct IC *p, int n_op,
+ int *r_z, int *r_q1, int *r_q2, long *k)
+{
+ int is32b;
+ int t = q1typ(p) & NQ;
+ int z;
+
+ /* Init */
+ gc->op_save = 0;
+
+ /* Type */
+ if (ISSCALAR(t) && (msizetab[t] == 1))
+ is32b = 0;
+ else if (ISSCALAR(t) && (msizetab[t] == 2))
+ is32b = 1;
+ else
+ ierror(0);
+
+ /* Where to place the destination ? */
+ if (r_z && isreg(&p->z))
+ z = p->z.reg;
+ else
+ z = is32b ? R_REP : R_RF; /* R_A is needed for the store_op */
+
+ if (r_z) *r_z = z;
+
+ /* Where can we load q1 ? */
+ if (isreg(&p->q1))
+ *r_q1 = p->q1.reg;
+ else if (isconst(&p->q1)) {
+ *r_q1 = R_I;
+ *k = const2long(&p->q1, q1typ(p));
+ } else {
+ if (isreg(&p->q2) || isconst(&p->q2) || (n_op < 2))
+ *r_q1 = R_A;
+ else
+ *r_q1 = z;
+ }
+
+ /* q2 ? */
+ if (n_op != 2)
+ return;
+
+ if (isreg(&p->q2))
+ *r_q2 = p->q2.reg;
+ else if (isconst(&p->q2)) {
+ *r_q2 = R_I;
+ *k = const2long(&p->q2, q2typ(p));
+ } else if (*r_q1 != z) {
+ *r_q2 = z;
+ } else if (!is32b) {
+ *r_q2 = (*r_q1 == R_A) ? R_RE : R_A;
+ } else if (z != R_REP) {
+ *r_q2 = R_REP;
+ } else {
+ /* At this point we have nowhere safe to load a 32b q2 :/ */
+ *r_q2 = _gc_find_reg(gc, 1);
+ if (!*r_q2)
+ *r_q2 = R_RCP;
+ gc->op_save = !regscratch[*r_q2] ? *r_q2 : 0;
+ }
+
+ if (gc->op_save) {
+ struct rpair rp;
+ reg_pair(gc->op_save, &rp);
+ _gc_emit_mov(gc, R_A, rp.r1);
+ _gc_emit(gc, "\tstd\tA, [Y--]\n");
+ _gc_emit_mov(gc, R_A, rp.r2);
+ _gc_emit(gc, "\tstd\tA, [Y--]\n");
+ }
+}
+
+static void
+_gc_op_post(struct gc_state *gc, struct IC *p)
+{
+ if (gc->op_save) {
+ struct rpair rp;
+ reg_pair(gc->op_save, &rp);
+ _gc_emit(gc, "\tldd\tA, [Y++, $1]\n");
+ _gc_emit_mov(gc, rp.r2, R_A);
+ _gc_emit(gc, "\tldd\tA, [Y++, $1]\n");
+ _gc_emit_mov(gc, rp.r1, R_A);
+ }
+
+ gc->op_save = 0;
+}
+
+/* Load an object into a register */
+static void
+_gc_load_op(struct gc_state *gc, struct obj *q, int dst, int typf)
+{
+ struct rpair rp;
+
+ /* Source already in register ? */
+ if (isreg(q))
+ {
+ _gc_move_gpr(gc, dst, q->reg);
+ return;
+ }
+
+ /* Is this a dereference ? */
+ if (q->flags & DREFOBJ)
+ {
+ long ptr_imm = 0;
+ int ptr_reg = 0;
+
+ if (q->flags & KONST) {
+ /* Constant address load */
+ ptr_imm = const2long(q, pointer_type(q->v->vtyp));
+ } else if (q->flags & REG) {
+ /* Dereference value in register */
+ ptr_reg = q->reg;
+ } else {
+ /* Load variable content */
+ ptr_reg = R_A;
+ _gc_load_from_mem(gc, R_A, pointer_type(q->v->vtyp), zm2l(zl2zm(q->val.vlong)), 0, q->v);
+ }
+
+ /* Execute dereference */
+ _gc_load_from_mem(gc, dst, q->dtyp, ptr_imm, ptr_reg, NULL);
+ }
+ else
+ {
+ if (q->flags & KONST) {
+ /* Constant load */
+ long k = const2long(q, typf);
+
+ if (reg_pair(dst, &rp)) {
+ /* 32 bit */
+ long v = k & 0xffff;
+ v = _gc_emit_imm(gc, v);
+ _gc_emit(gc, "\tmov\tA, $%d\n", v);
+ _gc_emit_mov(gc, rp.r1, R_A);
+ v = (k >> 16) & 0xffff;
+ v = _gc_emit_imm(gc, v);
+ _gc_emit(gc, "\tmov\tA, $%d\n", v);
+ _gc_emit_mov(gc, rp.r2, R_A);
+ } else {
+ /* 16 bit */
+ k = _gc_emit_imm(gc, k);
+ _gc_emit(gc, "\tmov\tA, $%d\n", k);
+ _gc_emit_mov(gc, dst, R_A);
+ }
+ } else if (q->flags & VARADR) {
+ /* Variable address load */
+ int tiny = (pointer_type(q->v->vtyp) == DPOINTER) ? TINY_DMEM : TINY_PMEM;
+ long ofs = zm2l(zl2zm(q->val.vlong));
+ char *sym = sym_name(q->v);
+
+ if (!tiny) _gc_emit(gc, "\timm\t$(hi(%s+%d))\n", sym, ofs);
+ _gc_emit(gc, "\tmov\tA, [$(lo(%s+%d))]\n", sym, ofs);
+ _gc_emit_mov(gc, dst, R_A);
+ } else if (!(q->flags & REG)) {
+ /* Variable load */
+ _gc_load_from_mem(gc, dst, pointer_type(q->v->vtyp), zm2l(zl2zm(q->val.vlong)), 0, q->v);
+ }
+ }
+}
+
+/* Store a register into its final destination */
+static void
+_gc_store_op(struct gc_state *gc, struct obj *z, int src, int typf)
+{
+ struct rpair rp;
+ int reg;
+
+ /* Register destination ? */
+ if (isreg(z))
+ {
+ _gc_move_gpr(gc, z->reg, src);
+ return;
+ }
+
+ /* Is this a dereference ? */
+ if (z->flags & DREFOBJ)
+ {
+ long ptr_imm = 0;
+ int ptr_reg = 0;
+
+ if (z->flags & KONST) {
+ /* Constant address load */
+ ptr_imm = const2long(z, pointer_type(z->v->vtyp));
+ } else if (z->flags & REG) {
+ /* Dereference value in register */
+ ptr_reg = z->reg;
+ } else {
+ /* Load variable content */
+ ptr_reg = R_A;
+ _gc_load_from_mem(gc, R_A, pointer_type(z->v->vtyp), zm2l(zl2zm(z->val.vlong)), 0, z->v);
+ }
+
+ /* Execute dereference */
+ _gc_store_to_mem(gc, src, z->dtyp, ptr_imm, ptr_reg, NULL);
+ }
+ else if (z->flags & VAR)
+ {
+ /* Variable store */
+ _gc_store_to_mem(gc, src, pointer_type(z->v->vtyp), zm2l(zl2zm(z->val.vlong)), 0, z->v);
+ }
+ else
+ {
+ /* huh ? */
+ ierror(0);
+ }
+}
+
+
+static void
+gc_func_begin(struct gc_state *gc,
+ FILE *f, struct IC *p, struct Var *v, zmax offset)
+{
+ int i;
+
+ /* Reset state */
+ memset(gc, 0x00, sizeof(struct gc_state));
+
+ gc->f = f;
+
+ /* Init register usage */
+ for (i=1; i<=MAXR; i++)
+ gc->reg_busy[i] = regsa[i];
+
+ /* Section and symbol setup */
+ if (isextern(v->storage_class))
+ emit(f, "\t.text\n%s%s:\n", idprefix, v->identifier);
+ else
+ emit(f, "\t.text\n%s%d:\n", labprefix, zm2l(v->offset));
+
+ /* Debug */
+#ifdef DBG
+ emit(gc->f, "\t; Function prologue\n");
+#endif
+
+ /* Function prologue */
+ /* Save return address */
+ emit(f, "\tmov\tA, X\n");
+ emit(f, "\tstd\tA, [Y--]\n");
+
+ /* Save all registers need saving */
+ for (i=1; i<=MAXR; i++) {
+ if (regused[i] && !regscratch[i] && !regsa[i])
+ {
+ struct rpair rp;
+ if (reg_pair(i, &rp)) {
+ if (!regused[rp.r1]) {
+ emit(f, "\tmov\tA, %s\n", regnames[rp.r1]);
+ emit(f, "\tstd\tA, [Y--]\n");
+ gc->s_savesize += 1;
+ }
+ if (!regused[rp.r2]) {
+ emit(f, "\tmov\tA, %s\n", regnames[rp.r2]);
+ emit(f, "\tstd\tA, [Y--]\n");
+ gc->s_savesize += 1;
+ }
+ } else {
+ emit(f, "\tmov\tA, %s\n", regnames[i]);
+ emit(f, "\tstd\tA, [Y--]\n");
+ gc->s_savesize += 1;
+ }
+ }
+ }
+
+ /* Adjust SP for local variables */
+ gc->s_localsize = zm2l(offset);
+
+ if (gc->s_localsize <= 2) {
+ for (i=0; i<gc->s_localsize; i++)
+ emit(f, "\tldd\tA, [Y--]\n"); /* Useless op */
+ } else {
+ emit(f, "\tmov\tA, Y\n");
+ emit(f, "\tadd\tA, A, $%d\n", -gc->s_localsize);
+ emit(f, "\tmov\tY, A\n");
+ }
+
+ /* Modifieds regs in all cases */
+ BSET(regs_modified, R_A);
+ BSET(regs_modified, R_X);
+ BSET(regs_modified, R_Y);
+}
+
+static void
+gc_func_end(struct gc_state *gc,
+ FILE *f, struct IC *p, struct Var *v, zmax offset)
+{
+ int i;
+
+ /* Debug */
+#ifdef DBG
+ emit(gc->f, "\n\t; Function epilogue\n");
+#endif
+
+ /* Function epilogue */
+ /* Re-adjust SP */
+ if (gc->s_localsize <= 2) {
+ for (i=0; i<gc->s_localsize; i++)
+ emit(f, "\tldd\tA, [Y++]\n"); /* Useless op */
+ } else {
+ emit(f, "\tmov\tA, Y\n");
+ emit(f, "\tadd\tA, A, $%d\n", gc->s_localsize);
+ emit(f, "\tmov\tY, A\n");
+ }
+
+ /* Restore saved registers */
+ for (i=MAXR; i>=1; i--) {
+ if (regused[i] && !regscratch[i] && !regsa[i])
+ {
+ struct rpair rp;
+ if (reg_pair(i, &rp)) {
+ if (!regused[rp.r2]) {
+ emit(f, "\tldd\tA, [Y++, $1]\n");
+ emit(f, "\tmov\t%s, A\n", regnames[rp.r2]);
+ }
+ if (!regused[rp.r1]) {
+ emit(f, "\tldd\tA, [Y++, $1]\n");
+ emit(f, "\tmov\t%s, A\n", regnames[rp.r1]);
+ }
+ } else {
+ emit(f, "\tldd\tA, [Y++, $1]\n");
+ emit(f, "\tmov\t%s, A\n", regnames[i]);
+ }
+ }
+ }
+
+ /* Return address */
+ emit(f, "\tldd\tA, [Y++, $1]\n");
+ emit(f, "\tmov\tX, A\n");
+
+ /* Return value */
+ emit(f, "\tbax\n");
+ if (gc->reg_rv)
+ emit(f, "\tmov\tA, %s\n", regnames[gc->reg_rv]);
+ else
+ emit(f, "\tmov\tA, $%d\n", gc->val_rv);
+
+ /* Bit of spacing */
+ emit(gc->f, "\n\n");
+}
+
+static void
+gc_func_assign(struct gc_state *gc, struct IC *node)
+{
+ /* FIXME: Only works for size=1 | size=2 ... */
+ int v_reg;
+
+ if (isreg(&node->q1)) {
+ v_reg = node->q1.reg;
+ } else {
+ v_reg = _gc_store_sel(node);
+ _gc_load_op(gc, &node->q1, v_reg, q1typ(node));
+ }
+
+ _gc_store_op(gc, &node->z, v_reg, ztyp(node));
+}
+
+static void
+gc_func_convert(struct gc_state *gc, struct IC *node)
+{
+ struct rpair rp;
+ int qt = q1typ(node) & NQ;
+ int zt = ztyp(node) & NQ;
+ int sext = !(q1typ(node) & UNSIGNED);
+ int v_reg;
+
+ if ((zt == LONG) && (qt >= CHAR) && (qt <= INT)) {
+ /* Convert from short to long */
+ v_reg = _gc_store_sel(node);
+
+ if (!reg_pair(v_reg, &rp))
+ ierror(0);
+
+ _gc_load_op(gc, &node->q1, rp.r1, q1typ(node));
+
+ if (sext) {
+ _gc_emit_alu(gc, "rol", R_A, rp.r1, 0, 0);
+ _gc_emit_alu(gc, "and", R_A, R_A, R_I, 1);
+ _gc_emit_alu(gc, "sub", R_A, R_A, R_I, 0);
+ _gc_emit_mov(gc, rp.r2, R_A);
+ } else {
+ _gc_emit(gc, "\tmov\tA, $0\n");
+ _gc_emit_mov(gc, rp.r2, R_A);
+ }
+ } else if ((zt >= CHAR) && (zt <= INT) && (qt == LONG)) {
+ /* Convert from long to short */
+ if (isreg(&node->q1)) {
+ /* Long already in register, so get the LSB from pair and do store */
+ if (!reg_pair(node->q1.reg, &rp))
+ ierror(0);
+
+ v_reg = rp.r1;
+ } else {
+ /* Perform a load as if it was a short. Because of Little-Endian, it works */
+ v_reg = _gc_store_sel(node);
+ _gc_load_op(gc, &node->q1, v_reg, q1typ(node));
+ }
+ } else if (ISPOINTER(zt) && ISPOINTER(qt)) {
+ /* No way to convert between pointer types to different spaces ... */
+ ierror(1);
+ } else {
+ /* Shouldn't happen, all other conversions are lib_call */
+ ierror(0);
+ }
+
+ _gc_store_op(gc, &node->z, v_reg, ztyp(node));
+}
+
+static void
+gc_func_alu_2op(struct gc_state *gc, struct IC *node)
+{
+ const char *opcode, *opcode2;
+ struct rpair rpz, rp1, rp2;
+ int regz, reg1, reg2, regt;
+ long k;
+ int is32b, issub, isadd;
+
+ is32b = ISTLONG(ztyp(node));
+ isadd = (node->code == ADD) || (node->code == ADDI2P);
+ issub = (node->code == SUB) || (node->code == SUBIFP) || (node->code == SUBPFP);
+
+ /* Load operands */
+ _gc_op_pre(gc, node, 2, ®z, ®1, ®2, &k);
+
+ if (!isreg(&node->q1) && !isconst(&node->q1))
+ _gc_load_op(gc, &node->q1, reg1, q1typ(node));
+
+ if (!isreg(&node->q2) && !isconst(&node->q2))
+ _gc_load_op(gc, &node->q2, reg2, q2typ(node));
+
+ /* We can only have immediate in reg2. Also 'sub' is swapped vs hw */
+ if (issub) {
+ if (reg2 == R_I) {
+ node->code = ADD;
+ k = -k;
+ } else {
+ regt = reg1;
+ reg1 = reg2;
+ reg2 = regt;
+ }
+ } else if (reg1 == R_I) {
+ regt = reg1;
+ reg1 = reg2;
+ reg2 = regt;
+ }
+
+ /* Solve reg-pairs */
+ reg_pair(regz, &rpz);
+ reg_pair(reg1, &rp1);
+ reg_pair(reg2, &rp2);
+
+ if (reg2 == R_I)
+ rp2.r1 = rp2.r2 = R_I;
+
+ /* Select opcode */
+ switch (node->code) {
+ case OR: opcode = "or"; opcode2 = "or"; break;
+ case XOR: opcode = "xor"; opcode2 = "xor"; break;
+ case AND: opcode = "and"; opcode2 = "and"; break;
+ case ADD: opcode = "add"; opcode2 = "addcy"; break;
+ case SUB: opcode = "sub"; opcode2 = "subcy"; break;
+ case ADDI2P: opcode = "add"; opcode2 = NULL; break;
+ case SUBIFP: opcode = "sub"; opcode2 = NULL; break;
+ case SUBPFP: opcode = "sub"; opcode2 = NULL; break;
+ default: ierror(0);
+ }
+
+ /* Do the operation */
+ if (is32b) {
+ if (regz == reg1) {
+ if (reg2 == R_I) {
+ /* 1 single GPR (reg1 == regz) and one immediate */
+ _gc_emit_alu(gc, opcode, rpz.r1, rp1.r1, R_I, k & 0xffff);
+ _gc_emit_alu(gc, opcode2, rpz.r2, rp1.r2, R_I, (k >> 16) & 0xffff);
+ } else {
+ /* 2 different GPRs, reg1 == regz */
+ _gc_emit_mov(gc, R_A, rp2.r1);
+ _gc_emit_alu(gc, opcode, rpz.r1, rp1.r1, R_A, 0);
+ _gc_emit_mov(gc, R_A, rp2.r2);
+ _gc_emit_alu(gc, opcode2, rpz.r2, rp1.r2, R_A, 0);
+ }
+ } else if (regz == reg2) {
+ /* 2 different GPRs, reg2 == regz */
+ _gc_emit_mov(gc, R_A, rp1.r1);
+ _gc_emit_alu(gc, opcode, rpz.r1, R_A, rp2.r1, 0);
+ _gc_emit_mov(gc, R_A, rp1.r2);
+ _gc_emit_alu(gc, opcode2, rpz.r2, R_A, rp2.r2, 0);
+ } else if (reg2 == R_I) {
+ /* 2 different GPRs and one immediate */
+ _gc_emit_mov(gc, R_A, rp1.r1);
+ _gc_emit_alu(gc, opcode, rpz.r1, R_A, rp2.r1, k & 0xffff);
+ _gc_emit_mov(gc, R_A, rp1.r2);
+ _gc_emit_alu(gc, opcode2, rpz.r2, R_A, rp2.r2, (k >> 16) & 0xffff);
+ } else {
+ /* 3 different GPRs pair */
+ _gc_emit_mov(gc, R_A, rp1.r1);
+ _gc_emit_alu(gc, opcode, R_A, R_A, rp2.r1, 0);
+ _gc_emit_mov(gc, rpz.r1, R_A);
+ _gc_emit_mov(gc, R_A, rp1.r2);
+ _gc_emit_alu(gc, opcode2, R_A, R_A, rp2.r2, 0);
+ _gc_emit_mov(gc, rpz.r2, R_A);
+ }
+ } else {
+ /* Count GPRs */
+ int ngpr = isgpr(regz) + isgpr(reg1) + isgpr(reg2);
+
+ /* Detect INC / DEC */
+ if ((reg2 == R_I) && ((k == 1) || (k == -1)) && (isadd || issub))
+ {
+ opcode = ((k == -1) ^ (node->code == SUB)) ? "dec" : "inc";
+
+ if ((regz == reg1) || (regz == R_A) || (reg1 == R_A)) {
+ _gc_emit_alu(gc, opcode, regz, reg1, 0, 0);
+ } else {
+ _gc_emit_alu(gc, opcode, R_A, reg1, 0, 0);
+ _gc_emit_mov(gc, regz, R_A);
+ }
+ }
+
+ /* Classic ALU */
+ else if (ngpr < 2) {
+ _gc_emit_alu(gc, opcode, regz, reg1, reg2, k);
+ } else if (ngpr == 2) {
+ if (regz == R_A) {
+ _gc_emit_mov(gc, R_A, reg1);
+ _gc_emit_alu(gc, opcode, R_A, R_A, reg2, k);
+ } else if ((regz == reg1) || (regz == reg2)) {
+ _gc_emit_alu(gc, opcode, regz, reg1, reg2, k);
+ } else {
+ _gc_emit_alu(gc, opcode, R_A, reg1, reg2, k);
+ _gc_emit_mov(gc, regz, R_A);
+ }
+ } else {
+ if (regz == reg1) {
+ _gc_emit_mov(gc, R_A, reg2);
+ _gc_emit_alu(gc, opcode, regz, regz, R_A, 0);
+ } else if (regz == reg2) {
+ _gc_emit_mov(gc, R_A, reg1);
+ _gc_emit_alu(gc, opcode, regz, regz, R_A, 0);
+ } else {
+ _gc_emit_mov(gc, R_A, reg1);
+ _gc_emit_alu(gc, opcode, R_A, R_A, reg2, 0);
+ _gc_emit_mov(gc, regz, R_A);
+ }
+ }
+ }
+
+ /* Store result */
+ _gc_store_op(gc, &node->z, regz, ztyp(node));
+
+ /* Allow 'test' optimization */
+ gc->cmp_cur_z = regz;
+
+ /* Clean up */
+ _gc_op_post(gc, node);
+}
+
+static void
+gc_func_not(struct gc_state *gc, struct IC *node)
+{
+ struct rpair rp;
+ int l_reg, z_reg, is32b;
+
+ z_reg = _gc_store_sel(node);
+ is32b = reg_pair(z_reg, &rp);
+ l_reg = (is32b || (isreg(&node->q1) && (node->q1.reg != z_reg))) ? z_reg : R_A;
+
+ _gc_load_op(gc, &node->q1, l_reg, q1typ(node));
+
+ if (is32b) {
+ _gc_emit(gc, "\tmov\tA, $0xffff\n");
+ _gc_emit_alu(gc, "xor", rp.r1, rp.r1, R_A, 0);
+ _gc_emit_alu(gc, "xor", rp.r2, rp.r2, R_A, 0);
+ } else {
+ _gc_emit_alu(gc, "xor", z_reg, l_reg, R_I, 0xffff);
+ }
+
+ _gc_store_op(gc, &node->z, z_reg, ztyp(node));
+}
+
+static void
+gc_func_neg(struct gc_state *gc, struct IC *node)
+{
+ struct rpair rp;
+ int l_reg, z_reg, is32b;
+
+ z_reg = _gc_store_sel(node);
+ is32b = reg_pair(z_reg, &rp);
+ l_reg = (is32b || (isreg(&node->q1) && (node->q1.reg != z_reg))) ? z_reg : R_A;
+
+ _gc_load_op(gc, &node->q1, l_reg, q1typ(node));
+
+ if (is32b) {
+ _gc_emit(gc, "\tmov\tA, $0\n");
+ _gc_emit_alu(gc, "sub", rp.r1, rp.r1, R_A, 0);
+ _gc_emit_alu(gc, "subcy", rp.r2, rp.r2, R_A, 0);
+ } else {
+ _gc_emit_alu(gc, "sub", z_reg, l_reg, R_I, 0);
+ }
+
+ _gc_store_op(gc, &node->z, z_reg, ztyp(node));
+}
+
+static void
+gc_func_shift(struct gc_state *gc, struct IC *node)
+{
+ /* FIXME */
+}
+
+static void
+gc_func_allocreg(struct gc_state *gc, struct IC *node)
+{
+ struct rpair rp;
+ int reg = node->q1.reg;
+
+ if (reg_pair(reg, &rp)) {
+ gc->reg_busy[rp.r1] = 1;
+ gc->reg_busy[rp.r2] = 1;
+ }
+ gc->reg_busy[reg] = 1;
+}
+
+static void
+gc_func_freereg(struct gc_state *gc, struct IC *node)
+{
+ int reg = node->q1.reg;
+ if (regsa[reg])
+ return;
+
+ if (reg_pair(reg, &rp)) {
+ gc->reg_busy[rp.r1] = 0;
+ gc->reg_busy[rp.r2] = 0;
+ }
+ gc->reg_busy[reg] = 0;
+}
+
+static void
+gc_func_cmp_test(struct gc_state *gc, struct IC *node)
+{
+ struct rpair rp1, rp2;
+ int reg1, reg2;
+ long k;
+ int istest, is32b;
+
+ istest = (node->code == TEST);
+ is32b = ISTLONG(q1typ(node));
+
+ /* Can this be optimized out ? */
+ if (istest && isreg(&node->q1) && (node->q1.reg == gc->cmp_cur_z))
+ return;
+
+ /* Load operands */
+ _gc_op_pre(gc, node, istest?1:2, NULL, ®1, ®2, &k);
+
+ if (!isreg(&node->q1) && !isconst(&node->q1))
+ _gc_load_op(gc, &node->q1, reg1, q1typ(node));
+
+ if (!istest && !isreg(&node->q2) && !isconst(&node->q2))
+ _gc_load_op(gc, &node->q2, reg2, q2typ(node));
+
+ reg_pair(reg1, &rp1);
+ reg_pair(reg2, &rp2);
+
+ if (reg2 == R_I)
+ rp2.r1 = rp2.r2 = R_I;
+
+ /* Do the compare */
+ if (is32b) {
+ /* 32b compare */
+ if (istest) {
+ _gc_emit_mov(gc, R_A, rp1.r2);
+ _gc_emit_alu(gc, "or", R_A, R_A, rp1.r1, 0);
+ } else {
+ _gc_emit_mov(gc, R_A, rp1.r1);
+ _gc_emit_alu(gc, "sub", R_A, R_A, rp2.r1, k & 0xffff);
+ _gc_emit_mov(gc, R_A, rp1.r2);
+ _gc_emit_alu(gc, "subcy", R_A, R_A, rp2.r2, (k >> 16) & 0xffff);
+ }
+ } else {
+ /* 16b compare */
+ if (node->code == TEST) {
+ _gc_emit_alu(gc, "test", 0, reg1, R_I, 0xffff);
+ } else {
+ _gc_emit_alu(gc, "cmp", 0, reg1, reg2, k);
+ }
+ }
+
+ /* Clean up */
+ _gc_op_post(gc, node);
+}
+
+static void
+gc_func_branch(struct gc_state *gc, struct IC *node)
+{
+ const char *cc, *ecc;
+ char label[16];
+
+ /* If q1 exists, it's the result of an lib_call compare */
+ if (node->q1.flags) {
+ int r;
+ if (isreg(&node->q1)) {
+ r = node->q1.reg;
+ } else {
+ _gc_load_op(gc, &node->q1, R_A, q1typ(node));
+ r = R_A;
+ }
+ _gc_emit_alu(gc, "cmp", 0, r, -1, 0);
+ gc->cmp_signed = 1;
+ }
+
+ /* Select condition code */
+ switch (node->code) {
+ case BRA: ecc = NULL; cc = ""; break;
+ case BEQ: ecc = NULL; cc = ".z"; break;
+ case BNE: ecc = NULL; cc = ".nz"; break;
+ case BLT: ecc = gc->cmp_signed ? "gt" : "hi"; cc = ".z"; break;
+ case BGE: ecc = gc->cmp_signed ? "gt" : "hi"; cc = ".nz"; break;
+ case BLE: ecc = gc->cmp_signed ? "ge" : "hs"; cc = ".z"; break;
+ case BGT: ecc = gc->cmp_signed ? "ge" : "hs"; cc = ".nz"; break;
+ default: ierror(0);
+ }
+
+ if (ecc)
+ _gc_emit(gc, "\tcc\t%s\n", ecc);
+
+ snprintf(label, sizeof(label)-1, "%s%d", labprefix, node->typf);
+ _gc_emit(gc, "\timm\t$hi(%s)\n", label);
+ _gc_emit(gc, "\tba%s\t$lo(%s)\n", cc, label);
+ _gc_emit_nop(gc);
+}
+
+static void
+gc_func_label(struct gc_state *gc, struct IC *node)
+{
+ _gc_emit(gc, "%s%d:\n", labprefix, node->typf);
+}
+
+static void
+gc_func_call(struct gc_state *gc, struct IC *node)
+{
+ if ((node->q1.flags & (VAR | DREFOBJ)) == VAR &&
+ node->q1.v->fi && node->q1.v->fi->inline_asm)
+ {
+ emit_inline_asm(gc->f, node->q1.v->fi->inline_asm);
+ }
+ else if (node->q1.flags & DREFOBJ)
+ {
+ /* Function pointer */
+ if (node->q1.dtyp != PPOINTER)
+ ierror(1);
+
+ if (node->q1.flags & KONST) {
+ /* Constant, do immediate jump */
+ long k = const2long(&node->q1, node->q1.dtyp);
+ k = _gc_emit_imm(gc, k);
+ _gc_emit(gc, "\tbal\t$%d\n", k);
+ } else {
+ /* Load variable into A */
+ if (node->q1.flags & REG)
+ _gc_emit_mov(gc, R_A, node->q1.reg);
+ else
+ _gc_load_from_mem(gc, R_A, pointer_type(node->q1.v->vtyp), zm2l(zl2zm(node->q1.val.vlong)), 0, node->q1.v);
+
+ /* Do the jump */
+ _gc_emit_mov(gc, R_X, R_A);
+ _gc_emit(gc, "\tbalx\tX\n");
+ }
+
+ _gc_emit_nop(gc);
+ }
+ else
+ {
+ char *sym = sym_name(node->q1.v);
+
+ if (!TINY_PMEM) _gc_emit(gc, "\timm\t$(hi(%s))\n", sym);
+ _gc_emit(gc, "\tbal\t$(lo(%s))\n", sym);
+
+ _gc_emit_nop(gc);
+ }
+
+ /* FIXME: fixup stack pointer after the call ?!? */
+}
+
+static void
+gc_func_push(struct gc_state *gc, struct IC *node)
+{
+ /* FIXME */
+}
+
+static void
+gc_func_getreturn(struct gc_state *gc, struct IC *node)
+{
+ int dst_reg;
+
+ /* Is it relevant at all ? */
+ if (!node->q1.reg) {
+ ierror(0);
+ return;
+ }
+
+ /* Is the target a register ? */
+ if (isreg(&node->z))
+ {
+ /* Yes, need move */
+ _gc_move_gpr(gc, node->z.reg, node->q1.reg);
+ } else {
+ /* Nope, not supported */
+ ierror(0);
+ }
+}
+
+static void
+gc_func_setreturn(struct gc_state *gc, struct IC *node)
+{
+ int src_reg;
+
+ /* Is it relevant at all ? */
+ if (!node->z.reg) {
+ ierror(0);
+ return;
+ }
+
+ /* Special case for small constants */
+ if ((node->z.reg == R_A) && isconst(&node->q1)) {
+ gc->val_rv = const2long(&node->q1, q1typ(node));
+ return;
+ }
+
+ /* Load value into register */
+ src_reg = node->z.reg;
+ _gc_load_op(gc, &node->q1, src_reg, q1typ(node));
+
+ /* If the target is R_A, we need to defer */
+ if (node->z.reg == R_A) {
+ if ((regscratch[src_reg] || regsa[src_reg]) && (src_reg != R_A)) {
+ gc->reg_rv = src_reg;
+ } else {
+ _gc_emit_mov(gc, R_A, src_reg);
+ _gc_emit_mov(gc, R_R0, R_A);
+ gc->reg_rv = R_R0;
+ gc->reg_lw = R_R0;
+ BSET(regs_modified, R_R0);
+ }
+ } else {
+ _gc_move_gpr(gc, node->z.reg, src_reg);
+ }
+}
+
+static void
+gc_func_movefromreg(struct gc_state *gc, struct IC *node)
+{
+ _gc_store_op(gc, &node->z, node->q1.reg, ztyp(node));
+}
+
+static void
+gc_func_movetoreg(struct gc_state *gc, struct IC *node)
+{
+ _gc_load_op(gc, &node->q1, node->z.reg, q1typ(node));
+}
+
+static void
+gc_func_address(struct gc_state *gc, struct IC *node)
+{
+ long sp_offset;
+
+ /* q1 is always an 'auto' (stack object) */
+ if (ztyp(node) != DPOINTER)
+ ierror(1);
+
+ if (!isauto(node->q1.v->storage_class))
+ ierror(0);
+
+ /* Compute real offset */
+ sp_offset = _gc_real_offset(gc, node->q1.v, zm2l(zl2zm(node->q1.val.vlong)));
+
+ _gc_emit_mov(gc, R_A, R_Y);
+ _gc_emit_alu(gc, "add", R_A, R_A, R_I, sp_offset);
+
+ /* Store it where we were asked */
+ _gc_store_op(gc, &node->z, R_A, ztyp(node));
+}
+
+static void
+gc_func_ic(struct gc_state *gc, struct IC *node)
+{
+ /* If nop, abort early */
+ if (node->code == NOP)
+ return;
+
+ /* Un-needed converts */
+ if (node->code == CONVERT && !must_convert(node->typf,node->typf2,0)) {
+ node->code = ASSIGN;
+ node->q2.val.vmax = sizetab[node->typf&NQ];
+ }
+
+ /* Debug */
+#ifdef DBG
+ emit(gc->f, "\n\t; %s\n", ename[node->code]);
+#endif
+
+ /* Main dispatch */
+#define GC_OP(c,n) case c: gc_func_ ## n (gc, node); break;
+
+ switch (node->code)
+ {
+ GC_OP(ASSIGN, assign)
+ GC_OP(CONVERT, convert)
+ GC_OP(OR, alu_2op)
+ GC_OP(XOR, alu_2op)
+ GC_OP(AND, alu_2op)
+ GC_OP(ADD, alu_2op)
+ GC_OP(SUB, alu_2op)
+ GC_OP(KOMPLEMENT, not)
+ GC_OP(MINUS, neg)
+ GC_OP(LSHIFT, shift)
+ GC_OP(RSHIFT, shift)
+ GC_OP(ALLOCREG, allocreg)
+ GC_OP(FREEREG, freereg)
+ GC_OP(COMPARE, cmp_test)
+ GC_OP(TEST, cmp_test)
+ GC_OP(BEQ ... BRA, branch)
+ GC_OP(LABEL, label)
+ GC_OP(CALL, call)
+ GC_OP(PUSH, push)
+ GC_OP(GETRETURN, getreturn)
+ GC_OP(SETRETURN, setreturn)
+ GC_OP(MOVEFROMREG, movefromreg)
+ GC_OP(MOVETOREG, movetoreg)
+ GC_OP(ADDRESS, address)
+ GC_OP(ADDI2P, alu_2op)
+ GC_OP(SUBIFP, alu_2op)
+ GC_OP(SUBPFP, alu_2op)
+
+ /* Those are always handled with libcall */
+ case MULT:
+ case DIV:
+ case MOD:
+ default:
+ break;//ierror(0);
+ }
+
+#undef GC_OP
+}
+
+
+/****************************************/
+/* End of private fata and functions. */
+/****************************************/
+
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+int init_cg(void)
+{
+ int i, j;
+
+ /* Macros */
+ target_macros = marray;
+
+ /* Alignement / size for types */
+ stackalign = l2zm(1L);
+ maxalign = l2zm(1L);
+ char_bit = l2zm(16L);
+
+ for (i=0; i<=MAX_TYPE; i++) {
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+
+ /* Registers */
+ regnames[0] = "noreg";
+
+ /* Defaults */
+ memset(regscratch, 0x00, sizeof(regscratch));
+ memset(regsa, 0x00, sizeof(regsa));
+ memset(reg_prio, 0x00, sizeof(reg_prio));
+
+ /* GPRs rX: 1-16 */
+ for (i=0; i<16; i++)
+ {
+ j = R_R0 + i;
+ regnames[j] = mymalloc(3);
+ sprintf(regnames[j], "r%x", i);
+ regsize[j] = l2zm(1L);
+ regtype[j] = &ityp;
+ }
+
+ /* GPRs sX: 17-32 */
+ for (i=0; i<16; i++)
+ {
+ j = R_S0 + i;
+ regnames[j] = mymalloc(3);
+ sprintf(regnames[j], "s%x", i);
+ regsize[j] = l2zm(1L);
+ regtype[j] = &ityp;
+ }
+
+ /* GPRs pair rXp: 33-40 */
+ for (i=0; i<8; i++)
+ {
+ j = R_R0P + i;
+ regnames[j] = mymalloc(3);
+ sprintf(regnames[j], "r%xp", 2*i);
+ regsize[j] = l2zm(2L);
+ regtype[j] = <yp;
+ }
+
+ /* GPRs pair sXp: 41-48 */
+ for (i=0; i<8; i++)
+ {
+ j = R_S0P + i;
+ regnames[j] = mymalloc(3);
+ sprintf(regnames[j], "s%xp", 2*i);
+ regsize[j] = l2zm(2L);
+ regtype[j] = <yp;
+ }
+
+ /* Use the first 8 registers as scratch
+ * registers */
+ for (i=0; i<8; i++) {
+ regscratch[R_R0 + i] = 1;
+ regscratch[R_S0 + i] = 1;
+ }
+
+ for (i=0; i<4; i++) {
+ regscratch[R_R0P + i] = 1;
+ regscratch[R_S0P + i] = 1;
+ }
+
+ /* Code gen internally uses re/rf pair */
+ regsa[R_RE] = regsa[R_RF] = regsa[R_REP] = 1;
+
+ /* Priority */
+ /* FIXME: TODO */
+
+ /* SPRs: 49-51 */
+ regnames[R_A] = "A";
+ regsize[R_A] = l2zm(1L);
+ regtype[R_A] = &ityp;
+ regsa[R_A] = 1; /* Special, used by codegen */
+
+ regnames[R_X] = "X";
+ regsize[R_X] = l2zm(1L);
+ regtype[R_X] = &ityp;
+ regsa[R_X] = 1; /* Link Register */
+
+ regnames[R_Y] = "Y";
+ regsize[R_Y] = l2zm(1L);
+ regtype[R_Y] = &ityp;
+ regsa[R_Y] = 1; /* Used as Stack pointer */
+
+ regnames[R_I] = "I";
+ regsize[R_I] = l2zm(1L);
+ regtype[R_I] = &ityp;
+ regsa[R_I] = 1; /* Virtual Immediate register */
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-32768L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=t_min[SHORT];
+ t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(32767UL);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=t_max[SHORT];
+ t_max[LONG]=ul2zum(2147483647UL);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(65535UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=tu_max[SHORT];
+ tu_max[LONG]=ul2zum(4294967295UL);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ /* Built-ins */
+#define UINT (UNSIGNED|INT)
+#define ULONG (UNSIGNED|LONG)
+#define ULLONG (UNSIGNED|LLONG)
+
+ /* 16 bit ops: lsl/lsr + mul/div/mod done in libcall */
+ declare_builtin("__lslint16", INT, INT, R_R0, INT, R_R1, 1, 0);
+ declare_builtin("__lsrint16", INT, INT, R_R0, INT, R_R1, 1, 0);
+ declare_builtin("__lsruint16", UINT, UINT, R_R0, INT, R_R1, 1, 0);
+
+ declare_builtin("__mulint16", INT, INT, R_R0, INT, R_R1, 1, 0);
+ declare_builtin("__divint16", INT, INT, R_R0, INT, R_R1, 1, 0);
+ declare_builtin("__divuint16", UINT, UINT, R_R0, UINT, R_R1, 1, 0);
+ declare_builtin("__modint16", INT, INT, R_R0, INT, R_R1, 1, 0);
+ declare_builtin("__moduint16", UINT, UINT, R_R0, UINT, R_R1, 1, 0);
+
+ /* 32 bit ops: lsl/lsr + mul/div/mod done in libcall */
+ declare_builtin("__lslint32", LONG, LONG, R_R0P, INT, R_R2, 1, 0);
+ declare_builtin("__lsrint32", LONG, LONG, R_R0P, INT, R_R2, 1, 0);
+ declare_builtin("__lsruint32", ULONG, ULONG, R_R0P, INT, R_R2, 1, 0);
+
+ declare_builtin("__mulint32", LONG, LONG, R_R0P, LONG, R_R2P, 1, 0);
+ declare_builtin("__divint32", LONG, LONG, R_R0P, LONG, R_R2P, 1, 0);
+ declare_builtin("__divuint32", ULONG, ULONG, R_R0P, ULONG, R_R2P, 1, 0);
+ declare_builtin("__modint32", LONG, LONG, R_R0P, LONG, R_R2P, 1, 0);
+ declare_builtin("__moduint32", ULONG, ULONG, R_R0P, ULONG, R_R2P, 1, 0);
+
+ /* 64 bits ops: everything done in libcall */
+ declare_builtin("__orint64", LLONG, LLONG, 0, LLONG, 0, 1, 0);
+ declare_builtin("__eorint64", LLONG, LLONG, 0, LLONG, 0, 1, 0);
+ declare_builtin("__andint64", LLONG, LLONG, 0, LLONG, 0, 1, 0);
+
+ declare_builtin("__lslint64", LLONG, LLONG, 0, INT, 0, 1, 0);
+ declare_builtin("__lsrint64", LLONG, LLONG, 0, INT, 0, 1, 0);
+ declare_builtin("__lsruint64", ULLONG, ULLONG, 0, INT, 0, 1, 0);
+
+ declare_builtin("__addint64", LLONG, LLONG, 0, LLONG, 0, 1, 0);
+ declare_builtin("__subint64", LLONG, LLONG, 0, LLONG, 0, 1, 0);
+
+ declare_builtin("__mulint64", LLONG, LLONG, 0, LLONG, 0, 1, 0);
+ declare_builtin("__divint64", LLONG, LLONG, 0, LLONG, 0, 1, 0);
+ declare_builtin("__divuint64", ULLONG, ULLONG, 0, ULLONG, 0, 1, 0);
+ declare_builtin("__modint64", LLONG, LLONG, 0, LLONG, 0, 1, 0);
+ declare_builtin("__moduint64", ULLONG, ULLONG, 0, ULLONG, 0, 1, 0);
+
+ declare_builtin("__negint64", LLONG, LLONG, 0, 0, 0, 1, 0);
+ declare_builtin("__notint64", LLONG, LLONG, 0, 0, 0, 1, 0);
+
+ declare_builtin("__cmpint64", INT, LLONG, 0, LLONG, 0, 1, 0);
+ declare_builtin("__cmpuint64", INT, ULLONG, 0, ULLONG, 0, 1, 0);
+
+ /* 64 bits conversions */
+ declare_builtin("__uint64touint16", ULLONG, UINT, R_R0, 0, 0, 1, 0);
+ declare_builtin("__uint64tosint16", ULLONG, INT, R_R0, 0, 0, 1, 0);
+ declare_builtin("__uint64touint32", ULLONG, ULONG, R_R0P, 0, 0, 1, 0);
+ declare_builtin("__uint64tosint32", ULLONG, LONG, R_R0P, 0, 0, 1, 0);
+
+ declare_builtin("__sint64touint16", LLONG, UINT, R_R0, 0, 0, 1, 0);
+ declare_builtin("__sint64tosint16", LLONG, INT, R_R0, 0, 0, 1, 0);
+ declare_builtin("__sint64touint32", LLONG, ULONG, R_R0P, 0, 0, 1, 0);
+ declare_builtin("__sint64tosint32", LLONG, LONG, R_R0P, 0, 0, 1, 0);
+
+ declare_builtin("__uint16touint64", UINT, ULLONG, 0, 0, 0, 1, 0);
+ declare_builtin("__sint16touint64", INT, ULLONG, 0, 0, 0, 1, 0);
+ declare_builtin("__uint32touint64", ULONG, ULLONG, 0, 0, 0, 1, 0);
+ declare_builtin("__sint32touint64", LONG, ULLONG, 0, 0, 0, 1, 0);
+
+ declare_builtin("__uint16tosint64", UINT, LLONG, 0, 0, 0, 1, 0);
+ declare_builtin("__sint16tosint64", INT, LLONG, 0, 0, 0, 1, 0);
+ declare_builtin("__uint32tosint64", ULONG, LLONG, 0, 0, 0, 1, 0);
+ declare_builtin("__sint32tosint64", LONG, LLONG, 0, 0, 0, 1, 0);
+
+ /* Float / Int conversions */
+ /* int16 */
+ declare_builtin("__sint16toflt32", FLOAT, INT, R_R0, 0, 0, 1, 0);
+ declare_builtin("__uint16toflt32", FLOAT, UINT, R_R0, 0, 0, 1, 0);
+ declare_builtin("__sint16toflt64", DOUBLE, INT, R_R0, 0, 0, 1, 0);
+ declare_builtin("__uint16toflt64", DOUBLE, UINT, R_R0, 0, 0, 1, 0);
+
+ declare_builtin("__flt32tosint16", INT, FLOAT, R_R0P, 0, 0, 1, 0);
+ declare_builtin("__flt32touint16", UINT, FLOAT, R_R0P, 0, 0, 1, 0);
+ declare_builtin("__flt64tosint16", INT, DOUBLE, 0, 0, 0, 1, 0);
+ declare_builtin("__flt64touint16", UINT, DOUBLE, 0, 0, 0, 1, 0);
+
+ /* int32 */
+ declare_builtin("__sint32toflt32", FLOAT, LONG, R_R0P, 0, 0, 1, 0);
+ declare_builtin("__uint32toflt32", FLOAT, ULONG, R_R0P, 0, 0, 1, 0);
+ declare_builtin("__sint32toflt64", DOUBLE, LONG, R_R0P, 0, 0, 1, 0);
+ declare_builtin("__uint32toflt64", DOUBLE, ULONG, R_R0P, 0, 0, 1, 0);
+
+ declare_builtin("__flt32tosint32", LONG, FLOAT, R_R0P, 0, 0, 1, 0);
+ declare_builtin("__flt32touint32", ULONG, FLOAT, R_R0P, 0, 0, 1, 0);
+ declare_builtin("__flt64tosint32", LONG, DOUBLE, 0, 0, 0, 1, 0);
+ declare_builtin("__flt64touint32", ULONG, DOUBLE, 0, 0, 0, 1, 0);
+
+ /* int64 */
+ declare_builtin("__sint64toflt32", FLOAT, LLONG, 0, 0, 0, 1, 0);
+ declare_builtin("__uint64toflt32", FLOAT, ULLONG, 0, 0, 0, 1, 0);
+ declare_builtin("__sint64toflt64", DOUBLE, LLONG, 0, 0, 0, 1, 0);
+ declare_builtin("__uint64toflt64", DOUBLE, ULLONG, 0, 0, 0, 1, 0);
+
+ declare_builtin("__flt32tosint64", LLONG, FLOAT, 0, 0, 0, 1, 0);
+ declare_builtin("__flt32touint64", ULLONG, FLOAT, 0, 0, 0, 1, 0);
+ declare_builtin("__flt64tosint64", LLONG, DOUBLE, 0, 0, 0, 1, 0);
+ declare_builtin("__flt64touint64", ULLONG, DOUBLE, 0, 0, 0, 1, 0);
+
+ /* Inter-Float conversions */
+ declare_builtin("__flt32toflt64", DOUBLE, FLOAT, 0, 0, 0, 1, 0);
+ declare_builtin("__flt64toflt32", FLOAT, DOUBLE, 0, 0, 0, 1, 0);
+
+ /* Floating point math */
+ /* float */
+ declare_builtin("__addflt32", FLOAT, FLOAT, R_R0P, FLOAT, R_R2P, 1, 0);
+ declare_builtin("__subflt32", FLOAT, FLOAT, R_R0P, FLOAT, R_R2P, 1, 0);
+ declare_builtin("__mulflt32", FLOAT, FLOAT, R_R0P, FLOAT, R_R2P, 1, 0);
+ declare_builtin("__divflt32", FLOAT, FLOAT, R_R0P, FLOAT, R_R2P, 1, 0);
+ declare_builtin("__negflt32", FLOAT, FLOAT, R_R0P, FLOAT, R_R2P, 1, 0);
+
+ declare_builtin("__cmpflt32", INT, FLOAT, R_R0P, FLOAT, R_R2P, 1, 0);
+
+ /* double */
+ declare_builtin("__addflt64", DOUBLE, DOUBLE, 0, DOUBLE, 0, 1, 0);
+ declare_builtin("__subflt64", DOUBLE, DOUBLE, 0, DOUBLE, 0, 1, 0);
+ declare_builtin("__mulflt64", DOUBLE, DOUBLE, 0, DOUBLE, 0, 1, 0);
+ declare_builtin("__divflt64", DOUBLE, DOUBLE, 0, DOUBLE, 0, 1, 0);
+ declare_builtin("__negflt64", DOUBLE, DOUBLE, 0, DOUBLE, 0, 1, 0);
+
+ declare_builtin("__cmpflt64", INT, DOUBLE, 0, DOUBLE, 0, 1, 0);
+
+#undef UINT
+#undef ULONG
+#undef ULLONG
+
+ return 1;
+}
+
+void cleanup_cg(FILE *f)
+{
+ /* Nothing to do */
+}
+
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+int freturn(struct Typ *t)
+{
+ int f = t->flags & NQ;
+
+ /* Any scalar that fits in 16 bits uses A as return register */
+ if (ISSCALAR(f) && (msizetab[f] == 1))
+ return R_A;
+
+ /* Any scalar that fits in 32 bits used R0/R1 as return register */
+ if (ISSCALAR(f) && (msizetab[f] == 2))
+ return R_R0P;
+}
+
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+int regok(int r, int t, int mode)
+{
+ if (r == 0)
+ return 0;
+
+ if (ISTSHORT(t)) {
+ if (r >= R_R0 && r <= R_RF)
+ return 1;
+ if (r >= R_S0 && r <= R_SF)
+ return 1;
+ if (r == R_A || r == R_X || r == R_Y)
+ return 1;
+ }
+
+ if (ISTLONG(t)) {
+ if (r >= R_R0P && r <= R_REP)
+ return 1;
+ if (r >= R_S0P && r <= R_SEP)
+ return 1;
+ }
+
+ return 0;
+}
+
+int dangerous_IC(struct IC *p)
+{
+ /* Only memory accesses are 'dangerous' */
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ return 0;
+}
+
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+int must_convert(int o,int t, int const_expr)
+{
+ int op=o&NQ,tp=t&NQ;
+
+ if (op==tp) return 0;
+
+ if (ISPOINTER(op) && ISPOINTER(tp))
+ return 1; /* No conversion actually possible between pointer types ! */
+
+ if (ISTSHORT(op) && ISTSHORT(tp))
+ return 0; /* All 'short' types are compatible */
+
+ return 1;
+}
+
+int shortcut(int code, int t)
+{
+ t &= NQ;
+ if (t == CHAR || t == SHORT || t == INT)
+ return 1;
+ return 0;
+}
+
+void gen_code(FILE *f, struct IC *p, struct Var *v, zmax offset)
+{
+ struct gc_state gc;
+ struct IC *node;
+
+ gc_func_begin(&gc, f, p, v, offset);
+ for (node=p; node; node=node->next)
+ gc_func_ic(&gc, node);
+ gc_func_end(&gc, f, p, v, offset);
+}
+
+void gen_ds(FILE *f, zmax size, struct Typ *t)
+{
+ long s = zm2l(size);
+ emit(f, "\t.space %ld\n", s);
+}
+
+void gen_align(FILE *f, zmax align)
+{
+ long a = zm2l(align);
+
+ if (a > 1)
+ emit(f, "\t.align %ld\n", a);
+}
+
+void gen_var_head(FILE *f, struct Var *v)
+{
+ const char*section_names[] = { /* bit 2: pmem, bit 1: init, bit 0: const */
+ "bss", NULL, "data", "rodata",
+ "pmem_bss", NULL, "pmem_data", "pmem_rodata",
+ };
+ int section_type;
+ struct Typ *tv;
+ char *attr;
+
+ tv = v->vtyp;
+ while (tv->flags==ARRAY)
+ tv = tv->next;
+ attr = tv->attr;
+
+ if (isstatic(v->storage_class) || isextern(v->storage_class))
+ {
+ /* Select section */
+ section_type = (attr && strstr(attr, STR_PMEM)) ? 4 : 0;
+ section_type |= v->clist ? 2 : 0;
+ section_type |= (v->clist && is_const(v->vtyp)) ? 1 : 0;
+
+ emit(f, "\t.section %s\n", section_names[section_type]);
+
+ /* Symbol name */
+ if (isstatic(v->storage_class))
+ emit(f, "%s%ld:\n", labprefix, zm2l(v->offset));
+ else
+ emit(f, "%s%s:\n", idprefix, v->identifier);
+
+ /* FIXME: export global symbols */
+ }
+ else
+ {
+ ierror(0);
+ }
+}
+
+void gen_dc(FILE *f, int t, struct const_list *p)
+{
+ const char *dct[] = { "", "byte", "short", "short", "long", "long", "long", "long" };
+ int tb;
+
+ if (ISPOINTER(t))
+ t = UNSIGNED|SHORT;
+ tb = t & NQ;
+
+ if (tb > LDOUBLE)
+ ierror(0);
+
+ emit(f, "\t.%s\t", dct[t&NQ]);
+
+ if (!p->tree)
+ {
+ if (ISFLOAT(tb)) {
+ unsigned char *ip;
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ if(tb != FLOAT){
+ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ } else if (tb == LLONG) {
+ /* Init */
+ zumax tmp;
+ eval_const(&p->val,t);
+ tmp = vumax;
+
+ /* Lower 32b */
+ vumax = zumand(tmp,ul2zum(0xffffffff));
+ gval.vulong = zum2zul(vumax);
+ emitval(f, &gval, UNSIGNED|LONG);
+
+ emit(f, ",");
+
+ /* Upper 32b */
+ vumax = zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff));
+ gval.vulong = zum2zul(vumax);
+ emitval(f, &gval, UNSIGNED|LONG);
+ } else {
+ emitval(f, &p->val, (t&NU)|UNSIGNED);
+ }
+ }
+ else
+ {
+ if ((p->tree->o.flags & (VAR | VARADR)) == (VAR | VARADR)) {
+ emit(f, "%s", sym_name(p->tree->o.v));
+ } else {
+ /* Not supported ... no idea what to do here */
+ ierror(0);
+ }
+ }
+
+ emit(f,"\n");
+}
+
+void init_db(FILE *f)
+{
+ /* not supported */
+}
+
+void cleanup_db(FILE *f)
+{
+ /* not supported */
+}
+
+/* Return name of library function, if this node should be
+ implemented via libcall. */
+char *use_libcall(int c,int t,int t2)
+{
+ static const char *names[] = { "na", "int16", "int16", "int16", "int32", "int64", "flt32", "flt64" };
+ static const struct {
+ int code;
+ int use_sign;
+ int types;
+ } lib_ops[] = {
+#define TB(x) (1 << (x))
+ { OR, 0, TB(LLONG) },
+ { XOR, 0, TB(LLONG) },
+ { AND, 0, TB(LLONG) },
+ { LSHIFT, 0, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) | TB(LONG) | TB(INT) | TB(SHORT) | TB(CHAR) },
+ { RSHIFT, 1, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) | TB(LONG) | TB(INT) | TB(SHORT) | TB(CHAR) },
+ { ADD, 0, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) },
+ { SUB, 0, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) },
+ { MULT, 0, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) | TB(LONG) | TB(INT) | TB(SHORT) | TB(CHAR) },
+ { DIV, 1, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) | TB(LONG) | TB(INT) | TB(SHORT) | TB(CHAR) },
+ { MOD, 1, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) | TB(LONG) | TB(INT) | TB(SHORT) | TB(CHAR) },
+ { COMPARE, 1, TB(DOUBLE) | TB(FLOAT) | TB(LLONG) },
+ { -1 }
+ };
+#undef TB
+ static char fname[20];
+ const char *n, *n2, *s, *s2;
+ int i;
+
+ /* We don't really support long doubles */
+ if (t==LDOUBLE) t=DOUBLE;
+ if (t2==LDOUBLE) t2=DOUBLE;
+
+ /* Safety */
+ if (((t&NQ) < CHAR) || ((t&NQ) > DOUBLE))
+ return NULL;
+ if ((t2&NQ) > DOUBLE)
+ return NULL;
+
+ /* Get name string for t/t2 and sign char */
+ n = names[t & NQ]; s = ISFLOAT(t) ? "" : ((t & UNSIGNED) ? "u" : "s");
+ n2 = names[t2 & NQ]; s2 = ISFLOAT(t2) ? "" : ((t2 & UNSIGNED) ? "u" : "s");
+
+ /* Conversions */
+ if (c == CONVERT)
+ {
+ /* Build name */
+ snprintf(fname, sizeof(fname)-1, "__%s%sto%s%s", s, n, s2, n2);
+
+ /* All conversion with float are library */
+ if (ISFLOAT(t) || ISFLOAT(t2))
+ return fname;
+
+ /* No match */
+ return NULL;
+ }
+
+ /* Scan for supported operations */
+ for (i=0; lib_ops[i].code > 0; i++)
+ {
+ /* Match op */
+ if (lib_ops[i].code != c)
+ continue;
+
+ /* Supported type ? */
+ if ((lib_ops[i].types & (1 << (t&NQ))) == 0)
+ return NULL;
+
+ /* Build name */
+ if (lib_ops[i].use_sign)
+ snprintf(fname, sizeof(fname)-1, "__%s%s%s", ename[c], s, n);
+ else
+ snprintf(fname, sizeof(fname)-1, "__%s%s", ename[c], n);
+
+ return fname;
+ }
+
+ return NULL;
+}
+
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+int reg_pair(int r,struct rpair *p)
+{
+ if ((r >= R_R0P) && (r <= R_REP))
+ {
+ p->r1 = R_R0 + 2 * (r - R_R0P);
+ p->r2 = R_R1 + 2 * (r - R_R0P);
+ return 1;
+ }
+
+ if ((r >= R_S0P) && (r <= R_SEP))
+ {
+ p->r1 = R_S0 + 2 * (r - R_S0P);
+ p->r2 = R_S1 + 2 * (r - R_S0P);
+ return 1;
+ }
+
+ return 0;
+}
+
+int reg_parm(struct reg_handle *p, struct Typ *t,int vararg,struct Typ *d)
+{
+ int f = t->flags & NQ;
+
+ /* Exclusions */
+ if (!ISSCALAR(f)) return 0;
+ if (p->gpr >= 4 || vararg) return 0;
+ if (f==LLONG || f==DOUBLE || f==LDOUBLE) return 0;
+
+ /* Pairs (possibly 'loosing' one reg if misaligned) */
+ if (f==LONG || f==FLOAT) {
+ p->gpr += (p->gpr & 1); /* align */
+ if (p->gpr >= 4)
+ return 0;
+ p->gpr += 2;
+ return R_R0P + (p->gpr / 2) - 1;
+ }
+
+ /* Normal */
+ return R_R0 + p->gpr++;
+}
+
+int pointer_type(struct Typ *p)
+{
+ while (ISARRAY(p->flags))
+ p=p->next;
+ if (ISFUNC(p->flags))
+ return PPOINTER;
+ if (p->attr && strstr(p->attr, STR_PMEM))
+ return PPOINTER;
+ return DPOINTER;
+}
+
+void conv_typ(struct Typ *p)
+{
+ char *attr;
+ while(p) {
+ if (ISPOINTER(p->flags)) {
+ p->flags = ((p->flags&~NU)|POINTER_TYPE(p->next));
+ if(attr=p->next->attr){
+ if(strstr(attr,STR_PMEM))
+ p->flags=((p->flags&~NU)|PPOINTER);
+ }
+ }
+ p=p->next;
+ }
+}
+
+/* Below is mostly copied from supp.c */
+void printval(FILE *f,union atyps *p,int t)
+{
+ t&=NU;
+ if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+ if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+ if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+ if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+ if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+ if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+ if(t==(UNSIGNED|INT)){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+ if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+ if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+ if(t==MAXINT){fprintf(f,"M");printzm(f,p->vmax);}
+ if(t==(UNSIGNED|MAXINT)){fprintf(f,"UM");printzum(f,p->vumax);}
+ if(t==DPOINTER){fprintf(f,"Pd");vumax=zul2zum(p->vushort);printzum(f,vumax);}
+ if(t==PPOINTER){fprintf(f,"Pp");vumax=zul2zum(p->vushort);printzum(f,vumax);}
+}
+
+void emitval(FILE *f,union atyps *p,int t)
+{
+ t&=NU;
+ if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+ if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+ if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+ if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+ if(t==LDOUBLE){emitzld(f,p->vldouble);}
+ if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+ if(t==(UNSIGNED|INT)){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+ if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+ if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+ if(t==MAXINT){emitzm(f,p->vmax);}
+ if(t==(UNSIGNED|MAXINT)){emitzum(f,p->vumax);}
+ if(t==DPOINTER){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+ if(t==PPOINTER){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+}
+
+void insert_const(union atyps *p,int t)
+{
+ if(!p) ierror(0);
+ t&=NU;
+ if(t==CHAR) {p->vchar=vchar;return;}
+ if(t==SHORT) {p->vshort=vshort;return;}
+ if(t==INT) {p->vint=vint;return;}
+ if(t==LONG) {p->vlong=vlong;return;}
+ if(t==LLONG) {p->vllong=vllong;return;}
+ if(t==MAXINT) {p->vmax=vmax;return;}
+ if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+ if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+ if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+ if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+ if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+ if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+ if(t==FLOAT) {p->vfloat=vfloat;return;}
+ if(t==DOUBLE) {p->vdouble=vdouble;return;}
+ if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+ if(t==DPOINTER) {p->vushort=vushort;return;}
+ if(t==PPOINTER) {p->vushort=vushort;return;}
+}
+
+void eval_const(union atyps *p,int t)
+{
+ int f=t&NQ;
+ if(!p) ierror(0);
+ if(f==MAXINT||(f>=CHAR&&f<=LLONG)){
+ if(!(t&UNSIGNED)){
+ if(f==CHAR) vmax=zc2zm(p->vchar);
+ else if(f==SHORT)vmax=zs2zm(p->vshort);
+ else if(f==INT) vmax=zi2zm(p->vint);
+ else if(f==LONG) vmax=zl2zm(p->vlong);
+ else if(f==LLONG) vmax=zll2zm(p->vllong);
+ else if(f==MAXINT) vmax=p->vmax;
+ else ierror(0);
+ vumax=zm2zum(vmax);
+ vldouble=zm2zld(vmax);
+ }else{
+ if(f==CHAR) vumax=zuc2zum(p->vuchar);
+ else if(f==SHORT)vumax=zus2zum(p->vushort);
+ else if(f==INT) vumax=zui2zum(p->vuint);
+ else if(f==LONG) vumax=zul2zum(p->vulong);
+ else if(f==LLONG) vumax=zull2zum(p->vullong);
+ else if(f==MAXINT) vumax=p->vumax;
+ else ierror(0);
+ vmax=zum2zm(vumax);
+ vldouble=zum2zld(vumax);
+ }
+ }else{
+ if(ISPOINTER(f)){
+ vumax=zus2zum(p->vushort);
+ vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+ }else{
+ if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+ else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+ else vldouble=p->vldouble;
+ vmax=zld2zm(vldouble);
+ vumax=zld2zum(vldouble);
+ }
+ }
+ vfloat=zld2zf(vldouble);
+ vdouble=zld2zd(vldouble);
+ vuchar=zum2zuc(vumax);
+ vushort=zum2zus(vumax);
+ vuint=zum2zui(vumax);
+ vulong=zum2zul(vumax);
+ vullong=zum2zull(vumax);
+ vchar=zm2zc(vmax);
+ vshort=zm2zs(vmax);
+ vint=zm2zi(vmax);
+ vlong=zm2zl(vmax);
+ vllong=zm2zll(vmax);
+}
diff --git a/machines/fire16/machine.dt b/machines/fire16/machine.dt
new file mode 100644
index 0000000..fa60647
--- /dev/null
+++ b/machines/fire16/machine.dt
@@ -0,0 +1,16 @@
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S16BULE S16BUBE
+
+
diff --git a/machines/fire16/machine.h b/machines/fire16/machine.h
new file mode 100644
index 0000000..f723321
--- /dev/null
+++ b/machines/fire16/machine.h
@@ -0,0 +1,189 @@
+/*
+ * Backend for the Fire16 iCE40 SoftCore
+ * (c) 2019 by Sylvain Munaut
+ */
+
+#include "dt.h"
+
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+struct AddressingMode {
+ int not_used_yet; // FIXME
+};
+
+/* The number of registers of the target machine. */
+ /* - 16 rN GPR + 8 pairs
+ * - 16 sN GPR + 8 pairs
+ * - A, X, Y, I
+ */
+#define MAXR 52
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 20
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P CHAR
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MAXADDI2P INT
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 0
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 1
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 16
+
+/* Parameters are sometimes passed in registers without __reg. */
+#define HAVE_REGPARMS 1
+
+/* Structure for reg_parm(). */
+struct reg_handle{
+ unsigned long gpr;
+};
+
+/* We have register pairs. */
+#define HAVE_REGPAIRS 1
+
+/* We use unsigned int as size_t rather than unsigned long which */
+/* is the default setting. */
+#define HAVE_INT_SIZET 1
+
+/* We have asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0 /* FIXME: not yet */
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES 1
+
+/* We do not have target-specific pragmas */
+#undef HAVE_TARGET_PRAGMAS
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt
+ register-allocation */
+#if 0 /* FIXME */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) XXX
+#define cost_load_reg(x,y) XXX
+#define cost_save_reg(x,y) XXX
+#define cost_pushpop_reg(x) XXX
+#endif
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+ optimizations on code which can already be implemented by efficient
+ assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we need extended types (for pmem/dmem pointers) */
+#define HAVE_EXT_TYPES 1
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef BOOL
+#undef MAXINT
+#undef MAX_TYPE
+
+#define CHAR 1
+#define SHORT 2
+#define INT 3
+#define LONG 4
+#define LLONG 5
+#define FLOAT 6
+#define DOUBLE 7
+#define LDOUBLE 8
+#define VOID 9
+#define DPOINTER 10
+#define PPOINTER 11
+#define ARRAY 12
+#define STRUCT 13
+#define UNION 14
+#define ENUM 15
+#define FUNKT 16
+#define BOOL 17
+#define MAXINT 18
+#define MAX_TYPE MAXINT
+
+#define POINTER_TYPE(x) pointer_type(x)
+extern int pointer_type();
+#define ISPOINTER(x) ((x&NQ)>=DPOINTER&&(x&NQ)<=PPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=CHAR&&(x&NQ)<=PPOINTER)
+#define ISINT(x) ((x&NQ)>=CHAR&&(x&NQ)<=LLONG)
+#define PTRDIFF_T(x) (INT)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+ zchar vchar;
+ zuchar vuchar;
+ zshort vshort;
+ zushort vushort;
+ zint vint;
+ zuint vuint;
+ zlong vlong;
+ zulong vulong;
+ zllong vllong;
+ zullong vullong;
+ zmax vmax;
+ zumax vumax;
+ zfloat vfloat;
+ zdouble vdouble;
+ zldouble vldouble;
+};
+
+
+/* we need our own printval */
+#define HAVE_TGT_PRINTVAL 1
+
+/* we want to replace some ICs with libcalls */
+#define HAVE_LIBCALLS 1
+
+/* we much prefer BNE */
+#define HAVE_WANTBNE 1
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
diff --git a/machines/generic/machine.c b/machines/generic/machine.c
new file mode 100755
index 0000000..f7b86ac
--- /dev/null
+++ b/machines/generic/machine.c
@@ -0,0 +1,1166 @@
+/* Example backend for vbcc, it models a generic 32bit RISC or CISC
+ CPU.
+
+ Configurable at build-time are:
+ - number of (32bit) general-purpose-registers
+ - number of (64bit) floating-point-registers
+ - number of (8bit) condition-code-registers
+ - mechanism for stack-arguments (moving ot fixed sp)
+
+ It allows to select as run-time-options:
+ - two- or three-address code
+ - memory operands or load-store-architecture
+ - number of register-arguments
+ - number of caller-save-registers
+*/
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc generic code-generator V0.1b (c) in 2001 by Volker Barthelmann";
+
+/* Commandline-flags the code-generator accepts:
+ 0: just a flag
+ VALFLAG: a value must be specified
+ STRINGFLAG: a string can be specified
+ FUNCFLAG: a function will be called
+ apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]={0,0,
+ VALFLAG,VALFLAG,VALFLAG,
+ 0,0,
+ VALFLAG,VALFLAG,0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+ they collide with the frontend */
+char *g_flags_name[MAXGF]={"three-addr","load-store",
+ "volatile-gprs","volatile-fprs","volatile-ccrs",
+ "imm-ind","gpr-ind",
+ "gpr-args","fpr-args","use-commons"};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. will be initialized in init_cg(),
+ register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+ estimated cost-saving can be obtained by several registers, the
+ one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__interrupt",0};
+
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+#define THREE_ADDR (g_flags[0]&USEDFLAG)
+#define LOAD_STORE (g_flags[1]&USEDFLAG)
+#define VOL_GPRS ((g_flags[2]&USEDFLAG)?g_flags_val[2].l:NUM_GPRS/2)
+#define VOL_FPRS ((g_flags[3]&USEDFLAG)?g_flags_val[3].l:NUM_FPRS/2)
+#define VOL_CCRS ((g_flags[4]&USEDFLAG)?g_flags_val[4].l:NUM_CCRS/2)
+#define IMM_IND ((g_flags[5]&USEDFLAG)?1:0)
+#define GPR_IND ((g_flags[6]&USEDFLAG)?2:0)
+#define GPR_ARGS ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:0)
+#define FPR_ARGS ((g_flags[8]&USEDFLAG)?g_flags_val[8].l:0)
+#define USE_COMMONS (g_flags[9]&USEDFLAG)
+
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]= {1,1,2,4,4,4,4,8,8,1,4,1,1,1,4,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp={LONG},ldbl={DOUBLE},lchar={CHAR};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+ "__GENERIC__",
+ 0};
+
+/* special registers */
+static int sp; /* Stackpointer */
+static int t1,t2,t3; /* temporary gprs */
+static int f1,f2,f3; /* temporary fprs */
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\t.text\n",
+ *dataname="\t.data\n",
+ *bssname="",
+ *rodataname="\t.section\t.rodata\n";
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+#if FIXED_SP
+/* variables to calculate the size and partitioning of the stack-frame
+ in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+#else
+/* variables to keep track of the current stack-offset in the case of
+ a moving stack-pointer */
+static long notpopped,dontpop,stackoffset,maxpushed;
+#endif
+
+static long localsize,rsavesize,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+ stack-pointer; we use a layout like this:
+ ------------------------------------------------
+ | arguments to this function |
+ ------------------------------------------------
+ | return-address [size=4] |
+ ------------------------------------------------
+ | caller-save registers [size=rsavesize] |
+ ------------------------------------------------
+ | local variables [size=localsize] |
+ ------------------------------------------------
+ | arguments to called functions [size=argsize] |
+ ------------------------------------------------
+ All sizes will be aligned as necessary.
+ In the case of FIXED_SP, the stack-pointer will be adjusted at
+ function-entry to leave enough space for the arguments and have it
+ aligned to 16 bytes. Therefore, when calling a function, the
+ stack-pointer is always aligned to 16 bytes.
+ For a moving stack-pointer, the stack-pointer will usually point
+ to the bottom of the area for local variables, but will move while
+ arguments are put on the stack.
+
+ This is just an example layout. Other layouts are also possible.
+*/
+
+static long real_offset(struct obj *o)
+{
+ long off=zm2l(o->v->offset);
+ if(off<0){
+ /* function parameter */
+ off=localsize+rsavesize+4-off-zm2l(maxalign);
+ }
+
+#if FIXED_SP
+ off+=argsize;
+#else
+ off+=stackoffset;
+#endif
+ off+=zm2l(o->val.vmax);
+ return off;
+}
+
+/* Initializes an addressing-mode structure and returns a pointer to
+ that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ am.offset=offset;
+ return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+ char *sec;
+ if(!v->vattr) return 0;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return 0;
+ sec+=strlen("section(");
+ emit(f,"\t.section\t");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/* Generates code to load the address of a variable into register r. */
+{
+ if(!(o->flags&VAR)) ierror(0);
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+ long off=real_offset(o);
+ if(THREE_ADDR){
+ emit(f,"\tadd.%s\t%s,%s,%ld\n",dt(POINTER),regnames[r],regnames[sp],off);
+ }else{
+ emit(f,"\tmov.%s\t%s,%s\n",dt(POINTER),regnames[r],regnames[sp]);
+ if(off)
+ emit(f,"\tadd.%s\t%s,%ld\n",dt(POINTER),regnames[r],off);
+ }
+ }else{
+ emit(f,"\tmov.%s\t%s,",dt(POINTER),regnames[r]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }
+}
+/* Generates code to load a memory object into register r. tmp is a
+ general purpose register which may be used. tmp can be r. */
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+ type&=NU;
+ if(o->flags&VARADR){
+ load_address(f,r,o,POINTER);
+ }else{
+ if((o->flags&(REG|DREFOBJ))==REG&&o->reg==r)
+ return;
+ emit(f,"\tmov.%s\t%s,",dt(type),regnames[r]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }
+}
+
+/* Generates code to store register r into memory object o. */
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+ type&=NQ;
+ emit(f,"\tmov.%s\t",dt(type));
+ emit_obj(f,o,type);
+ emit(f,",%s\n",regnames[r]);
+}
+
+/* Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+
+static struct IC *preload(FILE *,struct IC *);
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
+
+/* compare if two objects are the same */
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+ if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
+ return 1;
+ if(o1->flags==o2->flags&&o1->am==o2->am){
+ if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+ if(!(o1->flags®)||o1->reg==o2->reg){
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Does some pre-processing like fetching operands from memory to
+ registers etc. */
+static struct IC *preload(FILE *f,struct IC *p)
+{
+ int r;
+
+ if(isreg(q1))
+ q1reg=p->q1.reg;
+ else
+ q1reg=0;
+
+ if(isreg(q2))
+ q2reg=p->q2.reg;
+ else
+ q2reg=0;
+
+ if(isreg(z)&&(THREE_ADDR||!compare_objects(&p->q2,&p->z))){
+ zreg=p->z.reg;
+ }else{
+ if(ISFLOAT(ztyp(p)))
+ zreg=f1;
+ else
+ zreg=t1;
+ }
+
+ if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am){
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,t1,&p->q1,q1typ(p));
+ p->q1.reg=t1;
+ p->q1.flags|=(REG|DREFOBJ);
+ }
+ if(p->q1.flags&&LOAD_STORE&&!isreg(q1)){
+ if(p->code==ASSIGN&&isreg(z))
+ q1reg=p->z.reg;
+ else if(ISFLOAT(q1typ(p)))
+ q1reg=f1;
+ else
+ q1reg=t1;
+ load_reg(f,q1reg,&p->q1,q1typ(p));
+ p->q1.reg=q1reg;
+ p->q1.flags=REG;
+ }
+
+ if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am){
+ p->q2.flags&=~DREFOBJ;
+ load_reg(f,t1,&p->q2,q2typ(p));
+ p->q2.reg=t1;
+ p->q2.flags|=(REG|DREFOBJ);
+ }
+ if(p->q2.flags&&LOAD_STORE&&!isreg(q2)){
+ if(ISFLOAT(q2typ(p)))
+ q2reg=f2;
+ else
+ q2reg=t2;
+ load_reg(f,q2reg,&p->q2,q2typ(p));
+ p->q2.reg=q2reg;
+ p->q2.flags=REG;
+ }
+ return p;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+ if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
+ p->z.flags&=~DREFOBJ;
+ load_reg(f,t2,&p->z,POINTER);
+ p->z.reg=t2;
+ p->z.flags|=(REG|DREFOBJ);
+ }
+ if(isreg(z)){
+ if(p->z.reg!=zreg)
+ emit(f,"\tmov.%s\t%s,%s\n",dt(ztyp(p)),regnames[p->z.reg],regnames[zreg]);
+ }else{
+ store_reg(f,zreg,&p->z,ztyp(p));
+ }
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+ if(p->am){
+ if(p->am->flags&GPR_IND) emit(f,"(%s,%s)",regnames[p->am->offset],regnames[p->am->base]);
+ if(p->am->flags&IMM_IND) emit(f,"(%ld,%s)",p->am->offset,regnames[p->am->base]);
+ return;
+ }
+ if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if(p->flags&DREFOBJ) emit(f,"(");
+ if(p->flags®){
+ emit(f,"%s",regnames[p->reg]);
+ }else if(p->flags&VAR) {
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+ emit(f,"%ld(%s)",real_offset(p),regnames[sp]);
+ else{
+ if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ }
+ }
+ if(p->flags&KONST){
+ emitval(f,&p->val,t&NU);
+ }
+ if(p->flags&DREFOBJ) emit(f,")");
+}
+
+/* Test if there is a sequence of FREEREGs containing FREEREG reg.
+ Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+ while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+ if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+ p=p->next;
+ }
+ return 0;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+ int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+ for(;p;p=p->next){
+ c=p->code;
+ if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+ if(c==LABEL) exit_label=p->typf;
+
+ /* Try const(reg) */
+ if(IMM_IND&&(c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+ int base;zmax of;struct obj *o;
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ if(1/*zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))*/){
+ r=p->z.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ am->base=base;
+ am->offset=zm2l(of);
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+ /* Try reg,reg */
+ if(GPR_IND&&c==ADDI2P&&isreg(q2)&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+ int base,idx;struct obj *o;
+ r=p->z.reg;idx=p->q2.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||(q1typ(p2)&NQ)==LLONG) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||(q2typ(p2)&NQ)==LLONG) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||(ztyp(p2)&NQ)==LLONG) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=GPR_IND;
+ am->base=base;
+ am->offset=idx;
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+ rsavesize=0;
+ if(!special_section(f,v)&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+}
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+ emit(f,ret);
+}
+
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+int init_cg(void)
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(8L);
+ char_bit=l2zm(8L);
+ stackalign=l2zm(4);
+
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+
+ regnames[0]="noreg";
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"gpr%d",i-FIRST_GPR);
+ regsize[i]=l2zm(4L);
+ regtype[i]=<yp;
+ }
+ for(i=FIRST_FPR;i<=LAST_FPR;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"fpr%d",i-FIRST_FPR);
+ regsize[i]=l2zm(8L);
+ regtype[i]=&ldbl;
+ }
+ for(i=FIRST_CCR;i<=LAST_CCR;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"ccr%d",i-FIRST_CCR);
+ regsize[i]=l2zm(1L);
+ regtype[i]=&lchar;
+ }
+
+ /* Use multiple ccs. */
+ multiple_ccs=0;
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LONG]=t_min(INT);
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=ul2zum(2147483647UL);
+ t_max[LONG]=t_max(INT);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=ul2zum(4294967295UL);
+ tu_max[LONG]=t_max(UNSIGNED|INT);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ /* This is not optimal but simple. */
+ sp=FIRST_GPR;
+ t1=FIRST_GPR+1;
+ t2=FIRST_GPR+2;
+ f1=FIRST_FPR;
+ f2=FIRST_FPR+1;
+ regsa[t1]=regsa[t2]=1;
+ regsa[f1]=regsa[f2]=1;
+ regsa[sp]=1;
+ regscratch[t1]=regscratch[t2]=0;
+ regscratch[f1]=regscratch[f2]=0;
+ regscratch[sp]=0;
+
+ for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++)
+ regscratch[i]=1;
+ for(i=FIRST_FPR;i<=LAST_FPR-VOL_FPRS;i++)
+ regscratch[i]=1;
+ for(i=FIRST_CCR;i<=LAST_CCR-VOL_CCRS;i++)
+ regscratch[i]=1;
+
+ target_macros=marray;
+
+
+ return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+/* A pointer MUST be returned in a register. The code-generator */
+/* has to simulate a pseudo register if necessary. */
+{
+ if(ISFLOAT(t->flags))
+ return FIRST_FPR+2;
+ if(ISSTRUCT(t->flags)||ISUNION(t->flags))
+ return 0;
+ if(zmleq(szof(t),l2zm(4L)))
+ return FIRST_GPR+3;
+ else
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+ register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+ int c=p->code;
+ if(o->flags&VKONST){
+ if(!LOAD_STORE)
+ return 0;
+ if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
+ return 4;
+ else
+ return 2;
+ }
+ if(o->flags&DREFOBJ)
+ return 4;
+ if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+ if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+ return 2;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(r==0)
+ return 0;
+ t&=NQ;
+ if(t==0&&r>=FIRST_CCR&&r<=LAST_CCR)
+ return 1;
+ if(ISFLOAT(t)&&r>=FIRST_FPR&&r<=LAST_FPR)
+ return 1;
+ if(t==POINTER&&r>=FIRST_GPR&&r<=LAST_GPR)
+ return 1;
+ if(t>=CHAR&&t<=LONG&&r>=FIRST_GPR&&r<=LAST_GPR)
+ return 1;
+ return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* On the PowerPC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op=o&NQ,tp=t&NQ;
+ if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
+ return 0;
+ if(op==DOUBLE&&tp==LDOUBLE) return 0;
+ if(op==LDOUBLE&&tp==DOUBLE) return 0;
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ if(newobj&§ion!=SPECIAL)
+ emit(f,"%ld\n",zm2l(size));
+ else
+ emit(f,"\t.space\t%ld\n",zm2l(size));
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ if(zm2l(align)>1) emit(f,"\t.align\t2\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;char *sec;
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(v->clist||section==SPECIAL){
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }else
+ emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+ newobj=1;
+ }
+ if(v->storage_class==EXTERN){
+ emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+ if(v->flags&(DEFINED|TENTATIVE)){
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(v->clist||section==SPECIAL){
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ emit(f,"\tdc.%s\t",dt(t&NQ));
+ if(!p->tree){
+ if(ISFLOAT(t)){
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ if((t&NQ)!=FLOAT){
+ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ }else{
+ emitval(f,&p->val,t&NU);
+ }
+ }else{
+ emit_obj(f,&p->tree->o,t&NU);
+ }
+ emit(f,"\n");newobj=0;
+}
+
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/* The main code-generation. */
+{
+ int c,t,i;
+ struct IC *m;
+ argsize=0;
+ if(DEBUG&1) printf("gen_code()\n");
+ for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+ maxpushed=0;
+
+ /*FIXME*/
+ ret="\trts\n";
+
+ for(m=p;m;m=m->next){
+ c=m->code;t=m->typf&NU;
+ if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
+ if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
+
+ /* convert MULT/DIV/MOD with powers of two */
+ if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+ eval_const(&m->q2.val,t);
+ i=pof2(vmax);
+ if(i){
+ if(c==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ m->code=AND;
+ }else{
+ vmax=l2zm(i-1);
+ if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+ }
+ c=m->code;
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ if(c==AND){
+ insert_const(&m->q2.val,t);
+ }else{
+ insert_const(&m->q2.val,INT);
+ p->typf2=INT;
+ }
+ }
+ }
+#if FIXED_SP
+ if(c==CALL&&argsize<zm2l(m->q2.val.vmax)) argsize=zm2l(m->q2.val.vmax);
+#endif
+ }
+ peephole(p);
+
+ for(c=1;c<=MAXR;c++){
+ if(regsa[c]||regused[c]){
+ BSET(regs_modified,c);
+ }
+ }
+
+ localsize=(zm2l(offset)+3)/4*4;
+#if FIXED_SP
+ /*FIXME: adjust localsize to get an aligned stack-frame */
+#endif
+
+ function_top(f,v,localsize);
+
+#if FIXED_SP
+ pushed=0;
+#endif
+
+ for(;p;p=p->next){
+ c=p->code;t=p->typf;
+ if(c==NOP) {p->z.flags=0;continue;}
+ if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
+ if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
+ if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);continue;}
+ if(c==BRA){
+ if(0/*t==exit_label&&framesize==0*/)
+ emit(f,ret);
+ else
+ emit(f,"\tb\t%s%d\n",labprefix,t);
+ continue;
+ }
+ if(c>=BEQ&&c<BRA){
+ emit(f,"\tb%s\t",ccs[c-BEQ]);
+ if(isreg(q1)){
+ emit_obj(f,&p->q1,0);
+ emit(f,",");
+ }
+ emit(f,"%s%d\n",labprefix,t);
+ continue;
+ }
+ if(c==MOVETOREG){
+ load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+ continue;
+ }
+ if(c==MOVEFROMREG){
+ store_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+ continue;
+ }
+ if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+ ierror(0);
+ }
+ /* switch commutative operands if suitable */
+ if(c==ADD||c==MULT||c==AND||c==XOR||c==OR){
+ if(compare_objects(&p->q2,&p->z)){
+ struct obj tmp;
+ tmp=p->q1;
+ p->q1=p->q2;
+ p->q2=tmp;
+ }
+ }
+
+ p=preload(f,p);
+ c=p->code;
+ if(c==SUBPFP) c=SUB;
+ if(c==ADDI2P) c=ADD;
+ if(c==SUBIFP) c=SUB;
+ if(c==CONVERT){
+ if(ISFLOAT(q1typ(p))||ISFLOAT(ztyp(p))) ierror(0);
+ if(sizetab[q1typ(p)&NQ]<sizetab[ztyp(p)&NQ]){
+ if(q1typ(p)&UNSIGNED)
+ emit(f,"\tzext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+ else
+ emit(f,"\tsext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+ }
+ save_result(f,p);
+ continue;
+ }
+ if(c==KOMPLEMENT){
+ load_reg(f,zreg,&p->q1,t);
+ emit(f,"\tcpl.%s\t%s\n",dt(t),regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c==SETRETURN){
+ load_reg(f,p->z.reg,&p->q1,t);
+ BSET(regs_modified,p->z.reg);
+ continue;
+ }
+ if(c==GETRETURN){
+ if(p->q1.reg){
+ zreg=p->q1.reg;
+ save_result(f,p);
+ }else
+ p->z.flags=0;
+ continue;
+ }
+ if(c==CALL){
+ int reg;
+ /*FIXME*/
+#if 0
+ if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+ if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+ stack=framesize+zum2ul(p->q1.v->fi->stack1);
+ }else
+ stack_valid=0;
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ }else{
+ emit(f,"\tcall\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ /*FIXME*/
+#if FIXED_SP
+ pushed-=zm2l(p->q2.val.vmax);
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+ bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+ }else{
+ int i;
+ for(i=1;i<=MAXR;i++){
+ if(regscratch[i]) BSET(regs_modified,i);
+ }
+ }
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(t==0) ierror(0);
+ if(c==PUSH){
+#if FIXED_SP
+ emit(f,"\tmov.%s\t%ld(%s),",dt(t),pushed,regnames[sp]);
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ pushed+=zm2l(p->q2.val.vmax);
+#else
+ emit(f,"\tpush.%s\t",dt(t));
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ push(zm2l(p->q2.val.vmax));
+#endif
+ continue;
+ }
+ if(c==ASSIGN){
+ load_reg(f,zreg,&p->q1,t);
+ save_result(f,p);
+ }
+ continue;
+ }
+ if(c==ADDRESS){
+ load_address(f,zreg,&p->q1,POINTER);
+ save_result(f,p);
+ continue;
+ }
+ if(c==MINUS){
+ load_reg(f,zreg,&p->q1,t);
+ emit(f,"\tneg.%s\t%s\n",dt(t),regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c==TEST){
+ emit(f,"\ttst.%s\t",dt(t));
+ if(multiple_ccs)
+ emit(f,"%s,",regnames[zreg]);
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ if(multiple_ccs)
+ save_result(f,p);
+ continue;
+ }
+ if(c==COMPARE){
+ emit(f,"\tcmp.%s\t",dt(t));
+ if(multiple_ccs)
+ emit(f,"%s,",regnames[zreg]);
+ emit_obj(f,&p->q1,t);
+ emit(f,",");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ if(multiple_ccs)
+ save_result(f,p);
+ continue;
+ }
+ if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)){
+ if(!THREE_ADDR)
+ load_reg(f,zreg,&p->q1,t);
+ if(c>=OR&&c<=AND)
+ emit(f,"\t%s.%s\t%s,",logicals[c-OR],dt(t),regnames[zreg]);
+ else
+ emit(f,"\t%s.%s\t%s,",arithmetics[c-LSHIFT],dt(t),regnames[zreg]);
+ if(THREE_ADDR){
+ emit_obj(f,&p->q1,t);
+ emit(f,",");
+ }
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ save_result(f,p);
+ continue;
+ }
+ pric2(stdout,p);
+ ierror(0);
+ }
+ function_bottom(f,v,localsize);
+ if(stack_valid){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=stack;
+ }
+ emit(f,"# stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int code,int typ)
+{
+ return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+ int f;
+ f=t->flags&NQ;
+ if(f<=LONG||f==POINTER){
+ if(m->gregs>=GPR_ARGS)
+ return 0;
+ else
+ return FIRST_GPR+3+m->gregs++;
+ }
+ if(ISFLOAT(f)){
+ if(m->fregs>=FPR_ARGS)
+ return 0;
+ else
+ return FIRST_FPR+2+m->fregs++;
+ }
+ return 0;
+}
+
+int handle_pragma(const char *s)
+{
+}
+void cleanup_cg(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+ if(f) section=-1;
+}
+
diff --git a/machines/generic/machine.dt b/machines/generic/machine.dt
new file mode 100755
index 0000000..526c8d4
--- /dev/null
+++ b/machines/generic/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/generic/machine.h b/machines/generic/machine.h
new file mode 100755
index 0000000..118a4d7
--- /dev/null
+++ b/machines/generic/machine.h
@@ -0,0 +1,151 @@
+/* Example backend for vbcc, it models a generic 32bit RISC or CISC
+ CPU.
+
+ Configurable at build-time are:
+ - number of (32bit) general-purpose-registers
+ - number of (64bit) floating-point-registers
+ - number of (8bit) condition-code-registers
+ - mechanism for stack-arguments (moving ot fixed sp)
+
+ It allows to select as run-time-options:
+ - two- or three-address code
+ - memory operands or load-store-architecture
+ - number of register-arguments
+ - number of caller-save-registers
+*/
+
+/* buil-time configurable options: */
+#define NUM_GPRS 32
+#define NUM_FPRS 32
+#define NUM_CCRS 8
+#define FIXED_SP 1
+
+#include "dt.h"
+
+/* internally used by the backend */
+#define FIRST_GPR 1
+#define LAST_GPR (FIRST_GPR+NUM_GPRS-1)
+#define FIRST_FPR (LAST_GPR+1)
+#define LAST_FPR (FIRST_FPR+NUM_FPRS-1)
+#define FIRST_CCR (LAST_FPR+1)
+#define LAST_CCR (FIRST_CCR+NUM_CCRS-1)
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Currently possible are (const,gpr) and (gpr,gpr) */
+struct AddressingMode{
+ int flags;
+ int base;
+ long offset;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR NUM_GPRS+NUM_FPRS+NUM_CCRS
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 20
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P INT
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 1
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 0
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+/* Parameters are sometimes passed in registers without __reg. */
+#define HAVE_REGPARMS 1
+
+/* Parameters on the stack should be pushed in order rather than */
+/* in reverse order. */
+#define ORDERED_PUSH FIXED_SP
+
+/* Structure for reg_parm(). */
+struct reg_handle{
+ unsigned long gregs;
+ unsigned long fregs;
+};
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt
+ register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output, this can be used to do
+ peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/* We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+ optimizations on code which can already be implemented by efficient
+ assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+ etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#define HAVE_INT_SIZET 1
+
+/* we do not need register-pairs */
+#undef HAVE_REGPAIRS
+
+
+/* do not create CONVERT ICs from integers smaller than int to floats */
+#define MIN_INT_TO_FLOAT_TYPE INT
+
+/* do not create CONVERT ICs from floats to ints smaller than int */
+#define MIN_FLOAT_TO_INT_TYPE INT
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 1
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 1
+
+/* convert multiplications/division by powers of two to shifts */
+#define HAVE_POF2OPT 1
diff --git a/machines/hc12/machine.c b/machines/hc12/machine.c
new file mode 100755
index 0000000..c6bc237
--- /dev/null
+++ b/machines/hc12/machine.c
@@ -0,0 +1,3872 @@
+/* Code generator for Motorola 68hc12 microcontrollers. */
+
+/*TODO:
+ regs_modified bei struct-copy
+ savings verfeinern
+ 4-Byte Copy
+ [static] testen
+ peephole-Pass um ALLOCREGs zu entfernen
+ ACC_IND (Achtung?)
+ struct-copy Problemfälle
+ banked
+ bit
+ long long, float, double, long double
+
+*/
+
+#include "supp.h"
+#include "vbc.h" /* nicht schoen, aber ... */
+
+static char FILE_[]=__FILE__;
+
+#include "dwarf2.c"
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for 6809/6803/68hc12 V1.0 (c) in 2000-2021 by Volker Barthelmann";
+
+/* Commandline-flags the code-generator accepts */
+int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,
+ 0,0,0,0,
+ 0,0};
+char *g_flags_name[MAXGF]={"cpu","fpu","no-delayed-popping","const-in-data",
+ "merge-constants","no-peephole","mem-cse","acc-glob",
+ "pcrel","drel","no-char-addi2p","nodx","nou","double64"};
+union ppi g_flags_val[MAXGF];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","bit","char","short","int","long","long long",
+ "float","double","long double","void",
+ "near-pointer","far-pointer","huge-pointer",
+ "array","struct","union","enum","function"};
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT of the target machine. */
+zmax char_bit;
+
+/* Sizes of all elementary types in bytes. */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. */
+char *regnames[]={"noreg","d","x","y","sp","u","d/x"};
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* Type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1]={0,1,1,0,1,0,1};
+
+int reg_prio[MAXR+1]={0,0,1,1,0,0,1};
+
+struct reg_handle empty_reg_handle={0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__interrupt","__dpage",0};
+#define INTERRUPT 1
+#define DPAGE 2
+
+int MINADDI2P=CHAR;
+
+/****************************************/
+/* Some private data and functions. */
+/****************************************/
+
+static long malign[MAX_TYPE+1]= {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+static long msizetab[MAX_TYPE+1]={0,1,1,2,2,4,4,4,4,4,0,2,4,4,0,0,0,2,0};
+
+struct Typ ityp={SHORT},ltyp={LONG};
+
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static int section=-1,newobj,scnt,pushed_acc;
+static char *codename="\t.text\n",
+ *dataname="\t.data\n",
+ *bssname="\t.section\t.bss\n",
+ *rodataname="\t.section\t.rodata\n";
+
+#define IMM_IND 1
+#define VAR_IND 2
+#define POST_INC 3
+#define POST_DEC 4
+#define PRE_INC 5
+#define PRE_DEC 6
+#define ACC_IND 7
+#define KONSTINC 8
+
+/* (user)stack-pointer, pointer-tmp, int-tmp; reserved for compiler */
+static int acc=1,ix=2,iy=3,sp=4,iu=5,dx=6;
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+static char *marray[]={"__section(x,y)=__vattr(\"section(\"#x\",\"#y\")\")",
+ "__HC12__",
+ "__SIZE_T_INT=1",
+ "__direct=__vattr(\"section(\\\"dpage\\\")\")",
+ 0};
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static long loff,roff,stackoffset,notpopped,dontpop,maxpushed,stack;
+
+static char *x_t[]={"?","","b","","","","","","","","","","","","","",""};
+static char *ccs[]={"eq","ne","lt","ge","le","gt"};
+static char *uccs[]={"eq","ne","lo","hs","ls","hi"};
+static char *logicals[]={"ora","eor","and"};
+static char *dct[]={"",".bit",".byte",".2byte",".2byte",".4byte",".8byte",".4byte",".4byte",".4byte",
+ "(void)",".2byte",".34byte",".34byte"};
+static char *idprefix="",*labprefix=".l";
+static int exit_label,have_frame;
+static char *ret;
+static int stackchecklabel;
+static int frame_used,stack_valid;
+static int CPU=6812;
+static int pcrel,drel;
+static int skip_rel;
+static char *jsrinst="jsr";
+static char *jmpinst="jmp";
+static int nodx,nou;
+int switchsubs;
+
+static int cc_t;
+static struct obj *cc;
+
+static struct obj mobj;
+
+#define STR_NEAR "near"
+#define STR_FAR "far"
+#define STR_HUGE "huge"
+#define STR_BADDR "baddr"
+
+#define ISNULL() (zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
+#define ISLWORD(t) ((t&NQ)==LONG||(t&NQ)==FPOINTER||(t&NQ)==HPOINTER||ISFLOAT(t&NQ))
+#define ISHWORD(t) ((t&NQ)==INT||(t&NQ)==SHORT||(t&NQ)==NPOINTER)
+#define ISCHWORD(t) ((t&NQ)==CHAR||ISHWORD(t))
+#define ISCHAR(t) ((t&NQ)==CHAR)
+#define ISSTATIC(v) ((v)->storage_class==EXTERN||(v)->storage_class==STATIC)
+#define ISBADDR(v) ((v)->vtyp->attr&&strstr(STR_BADDR,(v)->vtyp->attr))
+/*FIXME*/
+#define ISFAR(v) ((v)->vtyp->attr&&(strstr(STR_FAR,(v)->vtyp->attr)||strstr(STR_HUGE,(v)->vtyp->attr)))
+
+#define ISACC(x) ((x)==acc)
+#define ISX(x) ((x)==ix)
+#define ISY(x) ((x)==iy)
+#define ISU(x) ((x)==iu)
+#define ISIDX(x) (ISX(x)||ISY(x)||(ISU(x)&&CPU!=6812))
+#define ISRACC(x) (isreg(x)&&ISACC(p->x.reg))
+#define ISRX(x) (isreg(x)&&ISX(p->x.reg))
+#define ISRY(x) (isreg(x)&&ISY(p->x.reg))
+#define ISRU(x) (isreg(x)&&ISU(p->x.reg))
+#define ISRIDX(x) (isreg(x)&&ISIDX(p->x.reg))
+
+#define CPUOPT ((g_flags[0]&USEDFLAG)?g_flags_val[0].l:6812)
+
+#define SPUSH(x) (CPU==6812?"\tpsh" x "\n":"\tpshs\t" x "\n")
+#define SPUSHD (CPU==6812?"\tpshd\n":"\tpshs\tb,a\n")
+#define SPULL(x) (CPU==6812?"\tpul" x "\n":"\tpuls\t" x "\n")
+#define SPULLD (CPU==6812?"\tpuld\n":"\tpuls\ta,b\n")
+#define SCMP(x) (CPU==6812?"\tcp" x "\t":"\tcmp" x "\t")
+#define SEX (CPU==6812?"\tsex\tb,d\n":"\tsex\n")
+#define EXTEND(t) (((t)&UNSIGNED)?"\tclra\n":SEX)
+
+#define SGN16(x) (zm2l(zi2zm(zm2zi(l2zm((long)(x))))))
+
+enum peepf { NEEDSAME = 1, REMOVE1ST = 2, ALLOWSFX = 4};
+struct peeps {char *s1,*s2,*r;enum peepf flags;};
+
+static int check_sfx(char *s)
+{
+ if(!*s) return 0;
+ s+=strlen(s)-1;
+ if(*s=='+'||*s=='-') return 1;
+ if(*s!='s'&&*s!='x'&&*s!='y'&&*s!='u') return 0;
+ s--;
+ if(*s!=',') return 0;
+ s--;
+ if(*s=='+'||*s=='-') return 1;
+ return 0;
+}
+
+static int setszflag(char *op,char r)
+{
+ static char *zb[]={"adcb","addb","andb","aslb","asrb","clrb","comb","decb","eorb","incb",
+ "ldab","ldb","lslb","lsrb","negb","orb","orab","rolb","rorb","sbcb",
+ "stb","stab","subb","tstb"};
+ static char *zd[]={"addd","ldd","sex","std","subd"};
+
+ int i;
+
+ if(r=='b'){
+ for(i=0;i<sizeof(zb)/sizeof(*zb);i++)
+ if(!strcmp(op,zb[i]))
+ return 1;
+ }
+ if(r=='d'){
+ for(i=0;i<sizeof(zd)/sizeof(*zd);i++)
+ if(!strcmp(op,zd[i]))
+ return 1;
+ }
+ if(r=='x'&&(!strcmp(op,"leax")||!strcmp(op,"ldx"))) return 1;
+ if(r=='y'&&(!strcmp(op,"leay")||!strcmp(op,"ldy"))) return 1;
+ if(CPU==6812){
+ if(r=='x'&&(!strcmp(op,"dex")||!strcmp(op,"inx"))) return 1;
+ if(r=='y'&&(!strcmp(op,"dey")||!strcmp(op,"iny"))) return 1;
+ }
+ return 0;
+}
+
+int emit_peephole(void)
+{
+ int entries,i,j,v1,v2;
+ char *asmline[EMIT_BUF_DEPTH];
+ char buf1[1024],buf2[1024];
+ char op1[8],op2[8];
+
+
+ /* TODO: adapt better */
+ static struct peeps elim[]={
+ "lda","sta",0,NEEDSAME,
+ "ldb","stb",0,NEEDSAME,
+ "ldaa","staa",0,NEEDSAME,
+ "ldab","stab",0,NEEDSAME,
+ "ldd","std",0,NEEDSAME,
+ "ldx","stx",0,NEEDSAME,
+ "ldy","sty",0,NEEDSAME,
+ "ldu","stu",0,NEEDSAME,
+ "sta","sta",0,NEEDSAME,
+ "stb","stb",0,NEEDSAME,
+ "staa","staa",0,NEEDSAME,
+ "stab","stab",0,NEEDSAME,
+ "std","std",0,NEEDSAME,
+ "stx","stx",0,NEEDSAME,
+ "sty","sty",0,NEEDSAME,
+ "stu","stu",0,NEEDSAME,
+ "sta","lda",0,NEEDSAME,
+ "stb","ldb",0,NEEDSAME,
+ "staa","ldaa",0,NEEDSAME,
+ "stab","ldab",0,NEEDSAME,
+ "std","ldd",0,NEEDSAME,
+ "stx","ldx",0,NEEDSAME,
+ "sty","ldy",0,NEEDSAME,
+ "stu","ldu",0,NEEDSAME,
+#if 0
+ "lda","lda",0,REMOVE1ST,
+ "ldaa","ldaa",0,REMOVE1ST,
+ "ldab","ldab",0,REMOVE1ST,
+ "ldb","ldb",0,REMOVE1ST,
+ "ldd","ldd",0,REMOVE1ST,
+ "ldx","ldx",0,REMOVE1ST,
+ "ldy","ldy",0,REMOVE1ST,
+ "ldu","ldu",0,REMOVE1ST,
+ "lda","pla",0,REMOVE1ST,
+ "lda","txa",0,REMOVE1ST,
+ "lda","tya",0,REMOVE1ST,
+ "ldx","tax",0,REMOVE1ST,
+ "ldy","tay",0,REMOVE1ST,
+ "tay","ldy",0,REMOVE1ST,
+ "tax","ldx",0,REMOVE1ST,
+ "txa","lda",0,REMOVE1ST,
+ "tya","lda",0,REMOVE1ST,
+#endif
+ };
+
+
+ i=emit_l;
+ if(emit_f==0)
+ entries=i-emit_f+1;
+ else
+ entries=EMIT_BUF_DEPTH;
+ asmline[0]=emit_buffer[i];
+ if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"cmpb")&&!strcmp(buf1,"#0"))
+ strcpy(asmline[0],"\ttstb\n");
+ if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"cmpd")&&!strcmp(buf1,"#0"))
+ strcpy(asmline[0],"\tsubd\t#0\n");
+
+ if(entries>=2){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[1]=emit_buffer[i];
+
+ for(j=0;j<sizeof(elim)/sizeof(elim[0]);j++){
+ if(elim[j].flags&NEEDSAME){
+ if(sscanf(asmline[0]," %6s %999s",op2,buf2)==2&&
+ sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&
+ !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)&&
+ !strcmp(buf1,buf2)){
+ if(!check_sfx(buf1)&&!check_sfx(buf2)){
+ if(elim[j].r){
+ strcpy(asmline[0],elim[j].r);
+ }else{
+ if(elim[j].flags&REMOVE1ST)
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ }
+ return 1;
+ }
+ }
+ }else{
+ *buf1=0;*buf2=0;
+ if(sscanf(asmline[1]," %6s %999s",op1,buf1)>=1&&
+ sscanf(asmline[0]," %6s %999s",op2,buf2)>=1&&
+ !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)){
+ if((elim[j].flags&ALLOWSFX)||(!check_sfx(buf1)&&!check_sfx(buf2))){
+ if(elim[j].flags&REMOVE1ST)
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return 1;
+ }
+ }
+ }
+ }
+
+ if(!strcmp(asmline[0],"\trts\n")&&sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"puls")){
+ sprintf(asmline[1]+strlen(asmline[1])-1,",pc\n");
+ remove_asm();
+ return 1;
+ }
+
+ if(!strcmp(asmline[0],"\tstb\t0,s\n")&&!strcmp(asmline[1],"\tleas\t-1,s\n")){
+ strcpy(asmline[1],"\tpshs\tb\n");
+ remove_asm();
+ return 1;
+ }
+
+ if(!strcmp(asmline[0],"\tstd\t0,s\n")&&!strcmp(asmline[1],"\tleas\t-2,s\n")){
+ strcpy(asmline[1],"\tpshs\tb,a\n");
+ remove_asm();
+ return 1;
+ }
+
+ if(!strcmp(asmline[0],"\tldb\t0,s\n")&&!strcmp(asmline[1],"\tpshs\tb\n")){
+ remove_asm();
+ return 1;
+ }
+
+ if(!strcmp(asmline[0],"\tldd\t0,s\n")&&!strcmp(asmline[1],"\tpshs\tb,a\n")){
+ remove_asm();
+ return 1;
+ }
+
+ if(!strcmp(asmline[0],"\tpshs\tb,a\n")&&!strcmp(asmline[1],"\tpuls\ta,b\n")){
+ strcpy(asmline[1],"\tldd\t0,s\n");
+ remove_asm();
+ return 1;
+ }
+
+ if(sscanf(asmline[1]," ldd %999s",op1)>=1&&sscanf(asmline[0]," ldd %999s",op2)>=1){
+ if(!((op2[0]=='a'||op2[0]=='b'||op2[0]=='d')&&op2[1]==',')){
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return 1;
+ }
+ }
+
+ if(!strcmp(asmline[0],"\ttfr\tx,d\n")&&!strcmp(asmline[1],"\ttfr\td,x\n")){
+ remove_asm();
+ return 1;
+ }
+ if(!strcmp(asmline[0],"\ttfr\ty,d\n")&&!strcmp(asmline[1],"\ttfr\td,y\n")){
+ remove_asm();
+ return 1;
+ }
+ if(!strcmp(asmline[0],"\tstd\t0,sp\n")&&!strcmp(asmline[1],"\tpshd\n")){
+ remove_asm();
+ return 1;
+ }
+ if(!strcmp(asmline[0],"\tldd\t0,sp\n")&&!strcmp(asmline[1],"\tpshd\n")){
+ remove_asm();
+ return 1;
+ }
+
+ if(sscanf(asmline[0]," leas %d,s",&v1)==1&&sscanf(asmline[1]," leas %d,s",&v2)==1){
+ sprintf(asmline[1],"\tleas\t%ld,s\n",SGN16(v1+v2));
+ remove_asm();
+ return 1;
+ }
+
+ if(CPU!=6812&&sscanf(asmline[0]," tfr %c,%c",buf1,buf2)==2){
+ if((*buf1=='x'||*buf1=='y'||*buf1=='u'||*buf1=='s')&&
+ (*buf2=='x'||*buf2=='y'||*buf2=='u'||*buf2=='s')){
+ sprintf(asmline[0],"\tlea%c\t,%c\n",*buf2,*buf1);
+ }
+ }
+ if(CPU==6812&&(!strcmp(asmline[1],"\tdex\n")||!strcmp(asmline[1],"\tdey\n")||!strcmp(asmline[1],"\tsubd\t#1\n"))&&
+ (!strncmp(asmline[0],"\tbne\t",5)||!strncmp(asmline[0],"\tbeq\t",5))){
+ char r=asmline[1][3];
+ if(r=='b') r='d';
+ strcpy(asmline[1],"\td");
+ strncpy(asmline[1]+2,asmline[0]+1,4);
+ asmline[1][6]=r;asmline[1][7]=',';
+ strcpy(asmline[1]+8,asmline[0]+5);
+ remove_asm();
+ return 1;
+ }
+ if(CPU==6812&&(!strcmp(asmline[1],"\tinx\n")||!strcmp(asmline[1],"\tiny\n")||!strcmp(asmline[1],"\taddd\t#1\n"))&&
+ (!strncmp(asmline[0],"\tbne\t",5)||!strncmp(asmline[0],"\tbeq\t",5))){
+ char r=asmline[1][3];
+ strcpy(asmline[1],"\ti");
+ strncpy(asmline[1]+2,asmline[0]+1,4);
+ asmline[1][6]=r;asmline[1][7]=',';
+ strcpy(asmline[1]+8,asmline[0]+5);
+ remove_asm();
+ return 1;
+ }
+ }
+ if(entries>=3){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[2]=emit_buffer[i];
+ if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2){
+ if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){
+ if(!strcmp(asmline[1],"\ttstb\n")||!strcmp(asmline[1],"\tcpb\t#0\n")){
+ if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+ setszflag(op2,'b')){
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return 1;
+ }
+ }
+ if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+ (!strcmp(op2,"subd")||!strcmp(op2,"cpd"))&&!strcmp(buf2,"#0")){
+ if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+ setszflag(op2,'d')){
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return 1;
+ }
+ }
+ if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+ !strcmp(op2,(CPU==6812)?"cpx":"cmpx")&&!strcmp(buf2,"#0")){
+ if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+ setszflag(op2,'x')){
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return 1;
+ }
+ }
+ if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+ !strcmp(op2,(CPU==6812)?"cpy":"cmpy")&&!strcmp(buf2,"#0")){
+ if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+ setszflag(op2,'y')){
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int special_section(FILE *f,struct Var *v)
+{
+ char *sec;
+ if(v->tattr&DPAGE){
+ emit(f,"\t.section\t.dpage\n");
+ }else{
+ if(!v->vattr) return 0;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return 0;
+ sec+=strlen("section(");
+ emit(f,"\t.section\t");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ }
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+static struct fpconstlist {
+ struct fpconstlist *next;
+ int label,typ;
+ union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+ struct fpconstlist *p=firstfpc;
+ t&=NQ;
+ if(g_flags[4]&USEDFLAG){
+ for(p=firstfpc;p;p=p->next){
+ if(t==p->typ){
+ eval_const(&p->val,t);
+ if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+ if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+ if(t==LDOUBLE&&zldeqto(vldouble,o->val.vldouble)) return p->label;
+ }
+ }
+ }
+ p=mymalloc(sizeof(struct fpconstlist));
+ p->next=firstfpc;
+ p->label=++label;
+ p->typ=t;
+ p->val=o->val;
+ firstfpc=p;
+ return p->label;
+}
+
+int pointer_type(struct Typ *p)
+{
+ if(!p) ierror(0);
+ while((p->flags&NQ)==ARRAY) p=p->next;
+ if((p->flags&NQ)==FUNKT) return NPOINTER; /*FIXME: banked*/
+ if(p->attr){
+ if(strstr(p->attr,STR_HUGE)) return HPOINTER;
+ if(strstr(p->attr,STR_FAR)) return FPOINTER;
+ if(strstr(p->attr,STR_NEAR)) return NPOINTER;
+ }
+ /*FIXME*/
+ return NPOINTER;
+}
+static long voff(struct obj *p)
+{
+ if(zm2l(p->v->offset)<0)
+ return loff-zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset+1;
+ else
+ return zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset;
+}
+
+static void emit_obj(FILE *f,struct obj *p,int t)
+/* Gibt Objekt auf Bildschirm aus */
+{
+ if(p->am){
+ int flags=p->am->flags;
+ if(flags==ACC_IND){
+ emit(f,"%s,%s",regnames[acc],regnames[p->am->base]);
+ return;
+ }
+ if(flags==KONSTINC){
+ eval_const(&p->val,p->am->base);
+ if(ISFLOAT(p->am->base)){
+ unsigned char *m=(unsigned char *)&p->val.vfloat;
+ if(zm2l(p->am->offset)==2)
+ emit(f,"#0x%02x%02x",m[2],m[3]);
+ else
+ emit(f,"#0x%02x%02x",m[0],m[1]);
+ return;
+ }else if((t&NQ)==CHAR){
+ vumax=zumrshift(vumax,24-8*p->am->offset);
+ vumax=zumand(vumax,ul2zum(255UL));
+ }else{
+ vumax=zumrshift(vumax,16-8*p->am->offset);
+ vumax=zumand(vumax,ul2zum(0xFFFFUL));
+ }
+ emit(f,"#%lu",zum2ul(vumax));
+ return;
+ }
+ if(flags<POST_INC||flags>PRE_DEC||CPU==6812)
+ emit(f,"%ld",p->am->offset&0xffff);
+ if(p->am->v){
+ if(p->am->v->storage_class==STATIC)
+ emit(f,"+%s%ld",labprefix,zm2l(p->am->v->offset));
+ else
+ emit(f,"+(%s%s)",idprefix,p->am->v->identifier);
+ }
+ emit(f,",");
+ if(flags==PRE_INC){
+ emit(f,"+");
+ if(p->am->offset==2&&CPU!=6812) emit(f,"+");
+ }else if(flags==PRE_DEC){
+ emit(f,"-");
+ if(p->am->offset==2&&CPU!=6812) emit(f,"-");
+ }
+ emit(f,"%s",regnames[p->am->base]);
+ if(flags==POST_INC){
+ emit(f,"+");
+ if(p->am->offset==2&&CPU!=6812) emit(f,"+");
+ }else if(flags==POST_DEC){
+ emit(f,"-");
+ if(p->am->offset==2&&CPU!=6812) emit(f,"-");
+ }
+ return;
+ }
+ if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if(p->flags&VARADR) emit(f,"#");
+ if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,"0,");
+ if((p->flags&(DREFOBJ|REG))==DREFOBJ) emit(f,"[");
+ if((p->flags&(VAR|REG))==VAR){
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+ emit(f,"%ld,%s",voff(p),regnames[sp]);
+ }else{
+ if(!zmeqto(l2zm(0L),p->val.vmax)){
+ emit(f,"%ld",zm2l(zi2zm(zm2zi(p->val.vmax))));
+ emit(f,"+");
+ }
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"(%s%s)",idprefix,p->v->identifier);
+ }
+ if(pcrel&&!(p->flags&VARADR)&&ISFUNC(p->v->vtyp->flags))
+ emit(f,",pc");
+ if(drel&&!(p->flags&VARADR)&&!ISFUNC(p->v->vtyp->flags)){
+ if(CPU==6812) ierror(0);
+ emit(f,",%s",regnames[iu]);
+ }
+ }
+ }
+ if(p->flags®){
+ if(ISACC(p->reg)&&(t&NQ)==CHAR)
+ emit(f,"b");
+ else
+ emit(f,"%s",regnames[p->reg]);
+ }
+ if(p->flags&KONST){
+ if(ISFLOAT(t)){
+ emit(f,"%s%d",labprefix,addfpconst(p,t));
+ }else{
+ emit(f,"#");emitval(f,&p->val,t&NU);
+ }
+ }
+ if((p->flags&(DREFOBJ|REG))==DREFOBJ){
+ if(p->v->storage_class==EXTERN||p->v->storage_class==STATIC){
+ if(is_const(p->v->vtyp)){
+ if(!pcrel&&CPU==6812) emit(f,",pc");
+ }else{
+ if(!drel&&CPU==6812) emit(f,",pc");
+ }
+ }
+ emit(f,"]");
+ }
+}
+
+static void dwarf2_print_frame_location(FILE *f,struct Var *v)
+{
+ /*FIXME: needs a location list and correct register translation */
+ struct obj o;
+ o.flags=REG;
+ o.reg=sp;
+ o.val.vmax=l2zm(0L);
+ o.v=0;
+ dwarf2_print_location(f,&o);
+}
+static int dwarf2_regnumber(int r)
+{
+ /*FIXME: always returns D as accumulator, even if byte size */
+ static int dwarf_regs[MAXR+1]={-1,3,7,8,15};
+ return dwarf_regs[r];
+}
+static zmax dwarf2_fboffset(struct Var *v)
+{
+ /*FIXME*/
+ if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0);
+ if(!zmleq(l2zm(0L),v->offset))
+ return l2zm((long)(loff-zm2l(v->offset)));
+ else
+ return v->offset;
+}
+
+/* test operand for mov instruction */
+static int mov_op(struct obj *o)
+{
+ long off;
+ if(CPU!=6812) return 0;
+ if(o->am){
+ int f=o->am->flags;
+ if(f==POST_INC||f==PRE_INC||f==POST_DEC||f==PRE_DEC||f==ACC_IND)
+ return 1;
+ if(f==IMM_IND){
+ if(o->am->v) return 0;
+ off=o->am->offset;
+ if(off>=-16&&off<=15)
+ return 1;
+ else
+ return 0;
+ }
+ ierror(0);
+ }
+ if(o->flags&(KONST|VARADR)) return 1;
+ if((o->flags&(REG|DREFOBJ))==(REG|DREFOBJ)) return 1;
+ if((o->flags&(VAR|REG|DREFOBJ))==VAR){
+ if(o->v->storage_class==STATIC||o->v->storage_class==EXTERN)
+ return 1;
+ off=voff(o);
+ if(off>=-16&&off<=15)
+ return 1;
+ else
+ return 0;
+ }
+ return 0;
+}
+
+/* add an offset to an object describing a memory address */
+static void inc_addr(struct obj *o,long val,int t)
+{
+ if(o->am){
+ int f=o->am->flags;
+ if(f==IMM_IND||f==KONSTINC)
+ o->am->offset+=val;
+ else if(f==POST_INC||f==POST_DEC||f==PRE_INC||f==PRE_DEC){
+ struct AddressingMode *old=o->am;
+ o->am=mymalloc(sizeof(*o->am));
+ o->am->flags=IMM_IND;
+ o->am->base=old->base;
+ o->am->v=0;
+ if(f==POST_DEC) o->am->offset=old->offset-val;
+ else if(f==POST_INC) o->am->offset=-old->offset+val;
+ else if(f==PRE_DEC) o->am->offset=val;
+ else o->am->offset=-val;
+ }else
+ ierror(0);
+ }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+ struct AddressingMode *am;
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ if(!o->reg) ierror(0);
+ am->base=o->reg;
+ am->offset=zm2l(val);
+ am->v=0;
+ }else if((o->flags&(DREFOBJ|KONST))==KONST){
+ struct AddressingMode *am;
+ if(o->am) ierror(0);
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=KONSTINC;
+ am->offset=zm2l(val);
+ am->base=t;
+ }else{
+ o->val.vmax=zmadd(o->val.vmax,val);
+ }
+}
+
+/* pushed on the stack by a callee, no pop needed */
+static void callee_push(long l)
+{
+ if(l-stackoffset>stack)
+ stack=l-stackoffset;
+}
+static void push(long l)
+{
+ stackoffset-=l;
+ if(stackoffset<maxpushed) maxpushed=stackoffset;
+ if(-maxpushed>stack) stack=-maxpushed;
+}
+static void pop(long l)
+{
+ stackoffset+=l;
+}
+static void gen_pop(FILE *f,long l)
+{
+ if(l==0) return;
+ if(l==1&&CPU==6812){
+ emit(f,"\tins\n");
+#if 0 /* might clobber return register */
+ }else if(l==2&&!regs[acc]){
+ emit(f,SPULLD);
+ BSET(regs_modified,acc);
+ }else if(l==2&&!regs[ix]){
+ emit(f,SPULL("x"));
+ BSET(regs_modified,ix);
+ }else if(l==2&&!regs[iy]){
+ emit(f,SPULL("y"));
+ BSET(regs_modified,iy);
+#endif
+ }else{
+ emit(f,"\tleas\t%u,%s\n",SGN16(l),regnames[sp]);
+ }
+ pop(l);
+}
+static void pr(FILE *f,struct IC *p)
+{
+ int r;
+ if(pushed_acc){
+ emit(f,SPULLD);
+ pop(2);
+ pushed_acc=0;
+ }
+ for(r=MAXR;r>=1;r--){
+ if(regs[r]&8){
+ emit(f,"\t%s%s\n",CPU==6812?"pul":"puls\t",regnames[r]);
+ pop(2);
+ }
+ regs[r]&=~12;
+ }
+}
+static void function_top(FILE *f,struct Var *v,long offset)
+/* erzeugt Funktionskopf */
+{
+ int i;
+ emit(f,"# offset=%ld\n",offset);
+ have_frame=0;stack_valid=1;stack=0;
+ if(!special_section(f,v)&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else{
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }
+ roff=0;
+ for(i=MAXR;i>0;i--){
+ if(regused[i]&&!regscratch[i]&&!regsa[i]){
+ have_frame=1;
+ loff+=2;
+ roff+=2;
+ if(i==iy) emit(f,SPUSH("y"));
+ else if(i==iu){
+ if(CPU!=6812&®used[iy]){
+ emit(f,"\tpshs\tu,y\n");
+ loff+=2;roff+=2;i=iy;
+ }else
+ emit(f,SPUSH("u"));
+ }else
+ ierror(0);
+ }
+ }
+ if(stack_check){
+ stackchecklabel=++label;
+ emit(f,"\tldy\t#%s%d\n",labprefix,stackchecklabel);
+ /* FIXME: banked */
+ emit(f,"\t%s\t%s__stack_check\n",jsrinst,idprefix);
+ }
+ if(offset){
+ if(CPU==6812&&offset==1)
+ emit(f,SPUSH("b"));
+ else if(CPU==6812&&offset==2)
+ emit(f,SPUSHD);
+ else
+ emit(f,"\tleas\t%ld,%s\n",SGN16(-offset),regnames[sp]);
+ have_frame=1;
+ }
+}
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/* erzeugt Funktionsende */
+{
+ int i;
+ offset-=roff;
+ if(offset){
+ if(offset==1&&CPU==6812)
+ emit(f,"\tins\n");
+ else if(offset==2&&CPU==6812&&!zmeqto(szof(v->vtyp->next),l2zm(4L)))
+ emit(f,SPULL("x"));
+ else if(offset==2&&CPU==6812&®used[iy])
+ emit(f,SPULL("y"));
+ else
+ emit(f,"\tleas\t%ld,%s\n",SGN16(offset),regnames[sp]);
+ }
+ for(i=1;i<=MAXR;i++){
+ if(regused[i]&&!regscratch[i]&&!regsa[i]){
+ have_frame=1;
+ if(i==iy){
+ if(CPU!=6812&®used[iu]&&!regscratch[iu]&&!regsa[iu]){
+ emit(f,"\tpuls\tu,y\n");
+ i=iu;
+ }else
+ emit(f,SPULL("y"));
+ }else if(i==iu) emit(f,SPULL("u"));
+ else
+ ierror(0);
+ }
+ }
+ if(ret) emit(f,"\t%s\n",ret);
+ if(v->storage_class==EXTERN){
+ emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+ emit(f,"\t.size\t%s%s,$-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
+ }else{
+ emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset));
+ emit(f,"\t.size\t%s%ld,$-%s%ld\n",labprefix,zm2l(v->offset),labprefix,zm2l(v->offset));
+ }
+ if(stack_check)
+ emit(f,"\t.equ\t%s%d,%ld\n",labprefix,stackchecklabel,offset-maxpushed);
+ if(stack_valid){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=l2zm(stack+offset);
+ emit(f,"# stacksize=%ld\n",stack+offset);
+ emit(f,"\t.equ\t%s__stack_%s,%ld\n",idprefix,v->identifier,stack+offset);
+ }
+}
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+ if(o1->flags==o2->flags&&o1->am==o2->am){
+ if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+ if(!(o1->flags®)||o1->reg==o2->reg){
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/*FIXME*/
+static void clear_ext_ic(struct ext_ic *p)
+{
+ p->flags=0;
+ p->r=0;
+ p->offset=0;
+}
+static long pof2(zumax x)
+/* Yields log2(x)+1 oder 0. */
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+static void peephole(struct IC *p)
+{
+ int c,c2,r,t;struct IC *p2;
+ struct AddressingMode *am;
+ zmax incmin,incmax;
+ if(CPU==6812){
+ incmin=l2zm(-8L);
+ incmax=l2zm(8L);
+ }else{
+ incmin=l2zm(-2L);
+ incmax=l2zm(2L);
+ }
+ frame_used=0;
+ for(;p;p=p->next){
+ c=p->code;
+ if(!frame_used){
+ if((p->q1.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q1.v)) frame_used=1;
+ if((p->q2.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q2.v)) frame_used=1;
+ if((p->z.flags&(REG|VAR))==VAR&&!ISSTATIC(p->z.v)) frame_used=1;
+ }
+ /* letztes Label merken */
+ if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+ if(c==LABEL) exit_label=p->typf;
+#if 0
+ /* and x,#const;bne/beq, FIXME */
+ if(c==AND&&isconst(q2)&&isreg(z)){
+ long bit;
+ eval_const(&p->q2.val,p->typf);
+ if(bit=pof2(vumax)){
+ struct IC *cmp=0;int fr=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==TEST){
+ if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg){
+ cmp=p2;continue;
+ }
+ }
+ if(c2==COMPARE&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,p2->typf);
+ if(ISNULL()){
+ cmp=p2;continue;
+ }
+ break;
+ }
+ if(c2==FREEREG&&p2->q1.reg==p->z.reg) {fr++;continue;}
+ if((c2==BNE||c2==BEQ)&&cmp&&fr==1){
+ p->ext.flags=EXT_IC_BTST;
+ p2->ext.flags=EXT_IC_BTST;
+ p2->ext.offset=bit-1;
+ cmp->code=NOP;
+ cmp->q1.flags=cmp->q2.flags=cmp->z.flags=0;
+ break;
+ }
+ if(((p2->q1.flags®)&&p2->q1.reg==p->z.reg)||((p2->q2.flags®)&&p2->q2.reg==p->z.reg)||((p2->z.flags®)&&p2->z.reg==p->z.reg)) break;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ }
+ }
+ }
+#endif
+ /* Try d,idx */
+ if(c==ADDI2P&&ISRACC(q2)&&ISRIDX(z)&&(ISRIDX(q1)||p->q2.reg!=p->z.reg)){
+ int base,idx;struct obj *o;
+ r=p->z.reg;idx=p->q2.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||!ISCHWORD(q1typ(p2))) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ break; /*TODO: check what is possible */
+ if(o||!ISCHWORD(q2typ(p2))) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ break; /*TODO: check what is possible */
+ if(o||!ISCHWORD(ztyp(p2))) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=ACC_IND;
+ am->base=base;
+ if(idx!=acc) ierror(0);
+ am->offset=idx;
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ /* better no instructions between, accu used too much */
+ if(c2!=FREEREG&&c2!=ALLOCREG&&!o) break;
+ }
+ }
+ /* POST_INC/DEC in q1 */
+ if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ r=p->q1.reg; t=q1typ(p);
+ if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q2.flags®)||p->q2.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,p2->typf2);
+ if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+ if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ p->q1.am=mymalloc(sizeof(*am));
+ p->q1.am->base=r;
+ p->q1.am->v=0;
+ if(zmleq(vmax,l2zm(0L))){
+ p->q1.am->flags=POST_DEC;
+ p->q1.am->offset=-zm2l(vmax);
+ }else{
+ p->q1.am->flags=POST_INC;
+ p->q1.am->offset=zm2l(vmax);
+ }
+ }else break;
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(((p2->q1.flags®)&&p2->q1.reg==r)||((p2->q2.flags®)&&p2->q2.reg==r)||((p2->z.flags®)&&p2->z.reg==r)) break;
+ }
+ }
+ }
+ /* POST_INC/DEC in q2 */
+ if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ r=p->q2.reg; t=q2typ(p);
+ if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q1.flags®)||p->q1.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,p2->typf2);
+ if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+ if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ p->q2.am=mymalloc(sizeof(*am));
+ p->q2.am->base=r;
+ p->q2.am->v=0;
+ if(zmleq(vmax,l2zm(0L))){
+ p->q2.am->flags=POST_DEC;
+ p->q2.am->offset=-zm2l(vmax);
+ }else{
+ p->q2.am->flags=POST_INC;
+ p->q2.am->offset=zm2l(vmax);
+ }
+ }else break;
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(((p2->q1.flags®)&&p2->q1.reg==r)||((p2->q2.flags®)&&p2->q2.reg==r)||((p2->z.flags®)&&p2->z.reg==r)) break;
+ }
+ }
+ }
+ /* POST_INC/DEC in z */
+ if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ r=p->z.reg; t=ztyp(p);
+ if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q1.flags®)||p->q1.reg!=r)&&(!(p->q2.flags®)||p->q2.reg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,p2->typf2);
+ if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+ if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ p->z.am=mymalloc(sizeof(*am));
+ p->z.am->base=r;
+ p->z.am->v=0;
+ if(zmleq(vmax,l2zm(0L))){
+ p->z.am->flags=POST_DEC;
+ p->z.am->offset=-zm2l(vmax);
+ }else{
+ p->z.am->flags=POST_INC;
+ p->z.am->offset=zm2l(vmax);
+ }
+ }else break;
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(((p2->q1.flags®)&&p2->q1.reg==r)||((p2->q2.flags®)&&p2->q2.reg==r)||((p2->z.flags®)&&p2->z.reg==r)) break;
+ }
+ }
+ }
+
+ /* R,#c */
+ if((c==ADDI2P||c==SUBIFP)&&ISHWORD(p->typf)&&((p->typf2&NQ)==NPOINTER||(p->typf2&NQ)==FPOINTER)&&isreg(z)&&((p->q2.flags&(KONST|DREFOBJ))==KONST||(!drel&&(p->q1.flags&VARADR)))){
+ int base;zmax of;struct obj *o;struct Var *v;
+ if(p->q1.flags&VARADR){
+ v=p->q1.v;
+ of=p->q1.val.vmax;
+ r=p->z.reg;
+ if(isreg(q2)&&ISIDX(p->q2.reg))
+ base=p->q2.reg;
+ else
+ base=r;
+ }else{
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ v=0;
+ r=p->z.reg;
+ if(isreg(q1)&&ISIDX(p->q1.reg)) base=p->q1.reg; else base=r;
+ }
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||!ISHWORD(q1typ(p2))) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||!ISHWORD(q2typ(p2))) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||!ISHWORD(ztyp(p2))) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ am->base=base;
+ am->offset=zm2l(of);
+ am->v=v;
+ if(!v){
+ if(isreg(q1)&&ISIDX(p->q1.reg)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }else{
+ if(isreg(q2)&&ISIDX(p->q2.reg)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q1=p->q2;p->q2.flags=0;
+ p->q2.val.vmax=sizetab[p->typf&NQ];
+ }
+ }
+ }
+ break;
+ }
+ if(/*get_reg!! c2!=FREEREG&&*/m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+}
+
+static struct obj *cam(int flags,int base,long offset,struct Var *v)
+/* Initializes an addressing-mode structure and returns a pointer to */
+/* that object. Will not survive a second call! */
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ am.offset=offset;
+ am.v=v;
+ return &obj;
+}
+
+static void get_acc(FILE *f,struct IC *p)
+{
+ if(regs[acc]){
+ if(p->q2.am)
+ if(p->q2.am->flags==ACC_IND) ierror(0);
+ else
+ if((p->q2.flags®)&&ISACC(p->q2.reg)) ierror(0);
+ if(p->z.am)
+ if(p->z.am->flags==ACC_IND) ierror(0);
+ else
+ if((p->z.flags®)&&ISACC(p->z.reg)) ierror(0);
+ if(regs[acc]){
+ emit(f,SPUSHD);
+ push(2);
+ pushed_acc=1;
+ }
+ }
+}
+static int get_idx(FILE *f,IC *p)
+{
+ int r;
+ for(r=1;r<=MAXR;r++){
+ if(ISIDX(r)){
+ if(!regs[r]){
+ regs[r]|=4;
+ return r;
+ }
+ }
+ }
+ for(r=1;r<=MAXR;r++){
+ if(ISIDX(r)){
+ if((!(p->q1.flags®)||p->q1.reg!=r)&&
+ (!(p->q2.flags®)||p->q2.reg!=r)&&
+ (!(p->z.flags®)||p->z.reg!=r)){
+ emit(f,"\t%s%s\n",CPU==6812?"psh":"pshs\t",regnames[r]);
+ regs[r]|=8;
+ push(2);
+ return r;
+ }
+ }
+ }
+ ierror(0);
+}
+static int get_reg(FILE *f,struct IC *p,int t)
+{
+ int reg;
+ if(!regs[acc])
+ reg=acc;
+ else if(ISHWORD(t)&&!regs[ix])
+ reg=ix;
+#if 0
+ else if(ISHWORD(t)&&!regs[iy])
+ reg=iy;
+#endif
+ else{
+ get_acc(f,p);
+ reg=acc;
+ }
+ BSET(regs_modified,reg);
+ return reg;
+}
+static void load_reg(FILE *f,int r,struct obj *o,int t)
+{
+ if(!o->am){
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg==r) return;
+ emit(f,"\ttfr\t%s,%s\n",regnames[o->reg],regnames[r]);
+ return;
+ }
+ if(r==acc&&(o->flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&o->val,t);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))){
+ if(CPU!=6812&&!optsize)
+ emit(f,"\tldd\t#0\n");
+ else
+ emit(f,"\tclra\n\tclrb\n");
+ cc=o;cc_t=t;
+ return;
+ }
+ }
+ }
+ if(o->flags&VARADR){
+ char *base=0;
+ if(pcrel&&ISFUNC(o->v->vtyp->flags))
+ base="pc";
+ if(drel&&!ISFUNC(o->v->vtyp->flags))
+ base=regnames[iu];
+ if(base&&!skip_rel){
+ if(ISACC(r))
+ emit(f,"\ttfr\t%s,d\n",base);
+ if(ISIDX(r))
+ emit(f,"\tlea%s\t",regnames[r]);
+ else{
+ if(*base=='p') emit(f,"%s%d:\n",labprefix,++label);
+ emit(f,"\taddd\t#");
+ }
+ emitzm(f,o->val.vmax);
+ emit(f,"+");
+ if(o->v->storage_class==EXTERN)
+ emit(f,"%s%s",idprefix,o->v->identifier);
+ else
+ emit(f,"%s%ld",labprefix,zm2l(o->v->offset));
+ if(ISIDX(r))
+ emit(f,",%s",base);
+ else if(*base=='p')
+ emit(f,"-%s%d",labprefix,label);
+ emit(f,"\n");
+ cc=o;cc_t=t;
+ return;
+ }
+ skip_rel=0;
+ }
+ emit(f,"\tld%s\t",(r==acc&&(t&NQ)==CHAR)?(CPU==6812?"ab":"b"):regnames[r]);
+ emit_obj(f,o,t);emit(f,"\n");
+ cc=o;cc_t=t;
+}
+static void store_reg(FILE *f,int r,struct obj *o,int t)
+{
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg==r) return;
+ emit(f,"\ttfr\t%s,%s\n",regnames[r],regnames[o->reg]);
+ }else{
+ if(r==acc&&(t&NQ)==CHAR)
+ emit(f,"\tst%s\t",(CPU==6812)?"ab":"b");
+ else
+ emit(f,"\tst%s\t",regnames[r]);
+ emit_obj(f,o,t);emit(f,"\n");
+ cc=o;cc_t=t;
+ }
+}
+static void load_addr(FILE *f,int r,struct obj *o)
+{
+ if(o->am){
+ if(o->am->flags==IMM_IND){
+ if(o->am->base==r&&o->am->offset==0&&!o->am->v) return;
+ if(ISIDX(r)){
+ emit(f,"\tlea%s\t",regnames[r]);
+ emit_obj(f,o,0);
+ emit(f,"\n");
+ }else{
+ if(r!=acc) ierror(0);
+ emit(f,"\ttfr\t%s,%s\n",regnames[o->am->base],regnames[r]);
+ emit(f,"\taddd\t#%ld\n",o->am->offset);
+ if(o->am->v){
+ if(o->am->v->storage_class==STATIC)
+ emit(f,"+%s%ld",labprefix,zm2l(o->am->v->offset));
+ else
+ emit(f,"+%s%s",idprefix,o->am->v->identifier);
+ }
+ emit(f,"\n");
+ cc=0;
+ }
+ return;
+ }
+ ierror(0);
+ }
+ if(o->flags&DREFOBJ){
+ o->flags&=~DREFOBJ;
+ load_reg(f,r,o,o->dtyp);
+ o->flags|=DREFOBJ;
+ return;
+ }
+ if((o->flags&(VAR|VARADR))==VAR){
+ if(o->v->storage_class==STATIC||o->v->storage_class==EXTERN){
+ o->flags|=VARADR;
+ load_reg(f,r,o,POINTER_TYPE(o->v->vtyp));
+ o->flags&=~VARADR;
+ return;
+ }
+ if(voff(o)==0){
+ emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[r]);
+ return;
+ }
+ if(ISIDX(r)){
+ emit(f,"\tlea%s\t",regnames[r]);
+ emit_obj(f,o,0);
+ emit(f,"\n");
+ }else{
+ if(r!=acc) ierror(0);
+ emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[r]);
+ emit(f,"\taddd\t#%ld\n",voff(o));
+ cc=0;
+ }
+ return;
+ }
+ ierror(0);
+}
+
+static int scratchreg(int r,struct IC *p)
+{
+ int c;
+ while(1){
+ p=p->next;
+ if(!p||((c=p->code)==FREEREG&&p->q1.reg==r)) return 1;
+ if(c==CALL||(c>=BEQ&&c<=BRA)) return 0;
+ if((p->q1.flags®)&&p->q1.reg==r) return 0;
+ if((p->q2.flags®)&&p->q2.reg==r) return 0;
+ if((p->z.flags®)&&p->z.reg==r) return 0;
+ }
+}
+
+/****************************************/
+/* End of private fata and functions. */
+/****************************************/
+
+
+int init_cg(void)
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+{
+ int i;
+
+ CPU=CPUOPT;
+
+ if(g_flags[13]&USEDFLAG){
+ msizetab[DOUBLE]=msizetab[LDOUBLE]=8;
+ dct[DOUBLE]=dct[LDOUBLE]=".8byte";
+ }
+
+
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(1L);
+ char_bit=l2zm(8L);
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+ for(i=1;i<=iu;i++){
+ regsize[i]=l2zm(2L);regtype[i]=&ityp;
+ }
+ regsize[dx]=l2zm(4L);regtype[i]=<yp;
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=t_min[SHORT];
+ t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=t_max[SHORT];
+ t_max[LONG]=ul2zum(2147483647UL);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=tu_max[SHORT];
+ tu_max[LONG]=ul2zum(4294967295UL);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ if(g_flags[9]&USEDFLAG) drel=1;
+ if(g_flags[10]&USEDFLAG) MINADDI2P=SHORT;
+ if(g_flags[11]&USEDFLAG) nodx=1;
+ if(g_flags[12]&USEDFLAG) nou=1;
+
+
+ if(CPU==6812) switchsubs=1;
+
+ /* Reserve a few registers for use by the code-generator. */
+ regsa[sp]=REGSA_NEVER;
+ regscratch[sp]=0;
+
+ if(CPU==6812||drel||nou){
+ regsa[iu]=REGSA_NEVER;
+ regscratch[iu]=0;
+ }
+
+ if(CPU!=6812){
+ regnames[sp]="s";
+ logicals[0]="or";
+ }
+
+ if(!(g_flags[6]&USEDFLAG)){
+ extern int static_cse,dref_cse;
+ static_cse=0;
+ dref_cse=0;
+ }
+
+ if(!(g_flags[7]&USEDFLAG)){
+ regsa[acc]=REGSA_TEMPS;
+ regsa[dx]=REGSA_TEMPS;
+ }
+
+ if(g_flags[8]&USEDFLAG){
+ pcrel=1;
+ jsrinst="lbsr";
+ jmpinst="lbra";
+ rodataname="\t.data\n";
+ }
+
+ if(CPU==6809)
+ marray[1]="__6809__";
+ if(CPU==6309)
+ marray[1]="__6309__";
+ if(CPU==9)
+ marray[1]="__TURBO9__";
+ target_macros=marray;
+
+
+ if(CPU==9||CPU==6812){
+ declare_builtin("__mulint16",INT,INT,acc,INT,iy,1,mystrdup("\temul"));
+ declare_builtin("__divint16",INT,INT,acc,INT,ix,1,mystrdup("\tidivs\n\ttfr\tx,d"));
+ declare_builtin("__divuint16",UNSIGNED|INT,UNSIGNED|INT,acc,UNSIGNED|INT,ix,1,mystrdup("\tidiv\n\ttfr\tx,d"));
+ declare_builtin("__modint16",INT,INT,acc,INT,ix,1,mystrdup("\tidivs"));
+ declare_builtin("__moduint16",UNSIGNED|INT,UNSIGNED|INT,acc,UNSIGNED|INT,ix,1,mystrdup("\tidiv"));
+ }else{
+ declare_builtin("__mulint16",INT,INT,acc,INT,0,1,0);
+ declare_builtin("__divint16",INT,INT,ix,INT,acc,1,0);
+ declare_builtin("__divuint16",UNSIGNED|INT,UNSIGNED|INT,ix,UNSIGNED|INT,acc,1,0);
+ declare_builtin("__modint16",INT,INT,ix,INT,acc,1,0);
+ declare_builtin("__moduint16",UNSIGNED|INT,UNSIGNED|INT,ix,UNSIGNED|INT,acc,1,0);
+ }
+
+ /* TODO: set argument registers */
+ declare_builtin("__mulint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__addint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__subint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__andint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__orint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__eorint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__negint32",LONG,LONG,0,0,0,1,0);
+ declare_builtin("__lslint32",LONG,LONG,0,INT,0,1,0);
+
+ declare_builtin("__divint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__divuint32",UNSIGNED|LONG,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0);
+ declare_builtin("__modint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__moduint32",UNSIGNED|LONG,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0);
+ declare_builtin("__lsrsint32",LONG,LONG,0,INT,0,1,0);
+ declare_builtin("__lsruint32",UNSIGNED|LONG,UNSIGNED|LONG,0,INT,0,1,0);
+ declare_builtin("__cmpsint32",INT,LONG,0,LONG,0,1,0);
+ declare_builtin("__cmpuint32",INT,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0);
+ declare_builtin("__sint32toflt32",FLOAT,LONG,0,0,0,1,0);
+ declare_builtin("__uint32toflt32",FLOAT,UNSIGNED|LONG,0,0,0,1,0);
+ declare_builtin("__sint32toflt64",DOUBLE,LONG,0,0,0,1,0);
+ declare_builtin("__uint32toflt64",DOUBLE,UNSIGNED|LONG,0,0,0,1,0);
+ declare_builtin("__flt32tosint32",LONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt32touint32",UNSIGNED|LONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt64tosint32",LONG,DOUBLE,0,0,0,1,0);
+ declare_builtin("__flt64touint32",UNSIGNED|LONG,DOUBLE,0,0,0,1,0);
+
+ declare_builtin("__sint16toflt32",FLOAT,INT,0,0,0,1,0);
+ declare_builtin("__uint16toflt32",FLOAT,UNSIGNED|INT,0,0,0,1,0);
+ declare_builtin("__sint16toflt64",DOUBLE,INT,0,0,0,1,0);
+ declare_builtin("__uint16toflt64",DOUBLE,UNSIGNED|INT,0,0,0,1,0);
+ declare_builtin("__flt32tosint16",INT,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt32touint16",UNSIGNED|INT,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt64tosint16",INT,DOUBLE,0,0,0,1,0);
+ declare_builtin("__flt64touint16",UNSIGNED|INT,DOUBLE,0,0,0,1,0);
+
+ declare_builtin("__sint8toflt32",FLOAT,CHAR,0,0,0,1,0);
+ declare_builtin("__uint8toflt32",FLOAT,UNSIGNED|CHAR,0,0,0,1,0);
+ declare_builtin("__sint8toflt64",DOUBLE,CHAR,0,0,0,1,0);
+ declare_builtin("__uint8toflt64",DOUBLE,UNSIGNED|CHAR,0,0,0,1,0);
+ declare_builtin("__flt32tosint8",CHAR,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt32touint8",UNSIGNED|CHAR,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt64tosint8",CHAR,DOUBLE,0,0,0,1,0);
+ declare_builtin("__flt64touint8",UNSIGNED|CHAR,DOUBLE,0,0,0,1,0);
+
+
+
+ declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__orint64" ,LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+ declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+ declare_builtin("__divsint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__modsint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__lsrsint64",LLONG,LLONG,0,INT,0,1,0);
+ declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+ declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
+ declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
+ declare_builtin("__sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
+ declare_builtin("__uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
+ declare_builtin("__flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
+ declare_builtin("__flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);
+
+ declare_builtin("__flt32toflt64",DOUBLE,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt64toflt32",FLOAT,DOUBLE,0,0,0,1,0);
+
+
+ declare_builtin("__addflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__subflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__mulflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__divflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__negflt32",FLOAT,FLOAT,0,0,0,1,0);
+ declare_builtin("__cmpflt32",CHAR,FLOAT,0,FLOAT,0,1,0);
+
+ declare_builtin("__addflt32 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__subflt32 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__mulflt32 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__divflt32 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__negflt32 ",DOUBLE,DOUBLE,0,0,0,1,0);
+ declare_builtin("__cmpflt32 ",CHAR,DOUBLE,0,DOUBLE,0,1,0);
+
+ declare_builtin("__addflt64 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__subflt64 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__mulflt64 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__divflt64 ",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__negflt64 ",DOUBLE,DOUBLE,0,0,0,1,0);
+ declare_builtin("__cmpflt64 ",CHAR,DOUBLE,0,DOUBLE,0,1,0);
+
+
+ return 1;
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+{
+ int f=t->flags&NQ;
+ if(ISSCALAR(f)){
+ if(ISHWORD(f)||f==CHAR)
+ return acc;
+ else if(ISLWORD(f))
+ return dx;
+ }
+ return 0;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(!ISSCALAR(t)) return 0;
+ if(r==dx){
+ if(ISLWORD(t)&&(optflags&2)&&!nodx) return 1;
+ return 0;
+ }
+ if(mode==-1){
+ if(ISHWORD(t)) return 1;
+ if((t&NQ)==CHAR&&ISACC(r)) return 1;
+ }else{
+ if(ISIDX(r)){
+ if(ISPOINTER(t)&&ISHWORD(t))
+ return 1;
+ }
+ if(ISACC(r)){
+ if((t&NQ)==CHAR)
+ return 1;
+ if(ISINT(t)&&ISHWORD(t))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ if(r==dx){
+ p->r1=acc;
+ p->r2=ix;
+ return 1;
+ }
+ return 0;
+}
+
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+ /*FIXME*/
+ int c=p->code;
+ if(r==dx){
+ if(c==GETRETURN||c==SETRETURN||c==PUSH||c==ASSIGN) return 8;
+ return INT_MIN;
+ }
+ if(o->flags&VKONST){
+ struct obj *co=&o->v->cobj;
+ if(o->flags&DREFOBJ)
+ return 0;
+ if(o==&p->q1&&p->code==ASSIGN&&((p->z.flags&DREFOBJ)||p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)){
+ return 2;
+ }
+ return 0;
+ }
+ if((o->flags&DREFOBJ)){
+ if(!ISIDX(r)) return INT_MIN;
+ if(p->q2.flags&&o!=&p->z)
+ return 6;
+ else
+ return 6;
+ }else if(c==GETRETURN&&p->q1.reg==r){
+ return 4;
+ }else if(c==SETRETURN&&p->z.reg==r){
+ return 4;
+ }else if(c==CONVERT&&((p->typf&NQ)==CHAR||(p->typf2&NQ)==CHAR)&®ok(r,CHAR,0)){
+ return 3;
+ }
+ if(o==&p->z&&r==acc){
+ if(c==SUB||c==SUBIFP||c==SUBPFP||c==AND||c==OR||c==XOR)
+ return 6;
+ if((c==ADD||c==ADDI2P)&&!(p->q1.flags&(KONST|VKONST))&&!(p->q2.flags&(KONST|VKONST)))
+ return 4;
+ if(c==MULT) return 5;
+ if(c==ASSIGN&&(p->q1.flags&KONST)){
+ eval_const(&p->q1.val,p->typf);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL)))
+ return 3;
+ }
+ }
+#if 1
+ if((o==&p->q2/*||o==&p->z*/)&&!(o->flags&DREFOBJ)&&!ISACC(o->reg)&&(c==MULT||c==DIV||c==MOD))
+ return INT_MIN;
+#endif
+ if(c==COMPARE||c==TEST){
+ if(r==ix) return 3;
+ if(r==iy) return 2;
+ if(r==iu) return 1;
+ }
+ return 2;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+/* Return name of library function, if this node should be
+ implemented via libcall. */
+char *use_libcall(int c,int t,int t2)
+{
+ static char fname[16];
+ char *ret=0;
+
+ if(c==COMPARE){
+ if((t&NQ)==LLONG){
+ sprintf(fname,"__cmp%sint32",(t&UNSIGNED)?"u":"s");
+ ret=fname;
+ }
+ if(ISFLOAT(t)){
+ return (t==FLOAT)?"__cmpflt32":"__cmpflt32 ";
+ ret=fname;
+ }
+
+ }else{
+ t&=NU;
+ t2&=NU;
+ if(t==LDOUBLE) t=DOUBLE;
+ if(t2==LDOUBLE) t2=DOUBLE;
+ if(c==CONVERT){
+ if(t==t2) return 0;
+ if(ISFLOAT(t)&&ISFLOAT(t2)) return 0;
+#if 0
+ /* currently support only 32bit flt */
+ if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+ if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+#endif
+ if(ISFLOAT(t)){
+ sprintf(fname,"__%cint%ldtoflt%ld",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ if(ISFLOAT(t2)){
+ sprintf(fname,"__flt%ldto%cint%ld",zm2l(sizetab[t2&NQ])*8,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+ if((t&NQ)==LLONG||ISFLOAT(t)){
+ if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+ if(t==(UNSIGNED|LLONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint64",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==LLONG){
+ sprintf(fname,"__%sint64",ename[c]);
+ ret=fname;
+ }else if(t==(UNSIGNED|LONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint32",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==LONG){
+ sprintf(fname,"__%sint32",ename[c]);
+ ret=fname;
+ }else{
+ sprintf(fname,"__%s%s%s%ld%s",ename[c],(c!=MULT&&(t&UNSIGNED))?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8,(t&NQ)>=DOUBLE?" ":"");
+ ret=fname;
+ }
+ }
+ }
+ if((c==MULT/*&&(CPU!=6812||(t&NQ)==LONG)*/)||c==DIV||c==MOD){
+ sprintf(fname,"__%s%s%s%ld%s",ename[c],(c!=MULT&&(t&UNSIGNED))?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8,(t&NQ)>=DOUBLE?" ":"");
+ ret=fname;
+ }
+ }
+
+ return ret;
+}
+
+
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+{
+ int op=o&NQ,tp=t&NQ;
+ if(op==tp) return 0;
+ if(ISFLOAT(op)){
+ if(ISFLOAT(tp)) return 0;
+ return 1;
+ }
+ if(ISFLOAT(tp)) return 1;
+ if(ISHWORD(op)&&ISHWORD(tp)) return 0;
+ if(ISFLOAT(op)||ISFLOAT(tp)) return 1;
+ if(ISLWORD(op)&&ISLWORD(tp)) return 0;
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ if(newobj&§ion!=SPECIAL)
+ emit(f,"%ld\n",zm2l(size));
+ else
+ emit(f,"\t.space\t%ld\n",zm2l(size));
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ /* nothing to do */
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(v->tattr&DPAGE)
+ emit(f,"\t.direct\t%s%ld\n",labprefix,zm2l(v->offset));
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&§ion!=DATA){
+ emit(f,dataname);if(f) section=DATA;
+ }
+ if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&§ion!=RODATA){
+ emit(f,rodataname);if(f) section=RODATA;
+ }
+ if(!v->clist&§ion!=BSS){
+ emit(f,bssname);if(f) section=BSS;
+ }
+ }
+ emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset));
+ emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp)));
+ if(v->clist||section==SPECIAL)
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ else
+ emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+ newobj=1;
+ }
+ if(v->storage_class==EXTERN){
+ if(v->flags&(DEFINED|TENTATIVE)){
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ if(v->tattr&DPAGE)
+ emit(f,"\t.direct\t%s%s\n",idprefix,v->identifier);
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&§ion!=DATA){
+ emit(f,dataname);if(f) section=DATA;
+ }
+ if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&§ion!=RODATA){
+ emit(f,rodataname);if(f) section=RODATA;
+ }
+ if(!v->clist&§ion!=BSS){
+ emit(f,bssname);if(f) section=BSS;
+ }
+ }
+ emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
+ emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp)));
+ if(v->clist||section==SPECIAL)
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ else
+ emit(f,"\t.global\t%s%s\n\t.lcomm\t%s%s,",idprefix,v->identifier,idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ emit(f,"\t%s\t",dct[t&NQ]);
+ if(!p->tree){
+ if(ISFLOAT(t)){
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+ ip=(unsigned char *)&p->val.vdouble;
+ if(zm2l(sizetab[t&NQ])==8){
+ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ }else{
+ emitval(f,&p->val,(t&NU)|UNSIGNED);
+ }
+ }else{
+ int m=p->tree->o.flags,md=drel,mp=pcrel;
+ p->tree->o.flags&=~VARADR;
+ drel=0;pcrel=0;
+ emit_obj(f,&p->tree->o,t&NU);
+ p->tree->o.flags=m;
+ drel=md;pcrel=mp;
+ }
+ emit(f,"\n");newobj=0;
+}
+
+
+static void preload(FILE *f,IC *p)
+{
+ int t,r;
+
+ if((p->typf&VOLATILE)||(p->typf2&VOLATILE)||
+ ((p->q1.flags&DREFOBJ)&&(p->q1.dtyp&(VOLATILE|PVOLATILE)))||
+ ((p->q2.flags&DREFOBJ)&&(p->q2.dtyp&(VOLATILE|PVOLATILE)))||
+ ((p->z.flags&DREFOBJ)&&(p->z.dtyp&(VOLATILE|PVOLATILE))))
+ emit(f,"; volatile barrier\n");
+
+ t=q1typ(p);
+ if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){
+ r=get_idx(f,p);
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,r,&p->q1,INT);
+ p->q1.flags|=(REG|DREFOBJ);
+ p->q1.reg=r;
+ }
+ t=q2typ(p);
+ if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){
+ r=get_idx(f,p);
+ p->q2.flags&=~DREFOBJ;
+ load_reg(f,r,&p->q2,INT);
+ p->q2.flags|=(REG|DREFOBJ);
+ p->q2.reg=r;
+ }else if(isreg(z)&&(((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg==p->z.reg)||(p->q2.am&&p->q2.am->base==p->z.reg))){
+ r=get_idx(f,p);
+ p->q2.flags&=~DREFOBJ;
+ load_reg(f,r,&p->q2,INT);
+ p->q2.flags|=(REG|DREFOBJ);
+ p->q2.reg=r;
+ }
+ t=ztyp(p);
+ if(!p->z.am&&(p->z.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){
+ r=get_idx(f,p);
+ p->z .flags&=~DREFOBJ;
+ load_reg(f,r,&p->z ,INT);
+ p->z .flags|=(REG|DREFOBJ);
+ p->z .reg=r;
+ }
+}
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+void gen_code(FILE *f,struct IC *fp,struct Var *v,zmax offset)
+{
+ int c,t,lastcomp=0,reg,short_add,bit_reverse,need_return=0;
+ struct obj *bit_obj;char *bit_reg;
+ static int idone;
+ struct obj o;
+ IC *p,*p2;
+ if(v->tattr&INTERRUPT)
+ ret="rti";
+ else
+ ret="rts"; /*FIXME: banked */
+ if(DEBUG&1) printf("gen_code()\n");
+ for(p=fp;p;p=p->next) clear_ext_ic(&p->ext);
+ emit(f,"#off1=%ld\n",zm2l(offset));
+ if(!(g_flags[5]&USEDFLAG)){
+ peephole(fp);
+ if(!frame_used) offset=l2zm(0L);
+ }
+ for(c=1;c<=MAXR;c++) regs[c]=(regsa[c]==REGSA_NEVER)?1:0;
+ for(c=1;c<=MAXR;c++){
+ if((regsa[c]==REGSA_NEVER||regused[c])){
+ BSET(regs_modified,c);
+ }
+ }
+ t=0;
+ for(p=fp;p;p=p->next){
+ c=p->code;
+ if(c==ALLOCREG){ regs[p->q1.reg]=1; if(p->q1.reg==dx) regs[acc]=regs[ix]=1;}
+ if(c==FREEREG){ regs[p->q1.reg]=0; if(p->q1.reg==dx) regs[acc]=regs[ix]=0;}
+ if((c==LSHIFT||c==RSHIFT)&&(p->typf&NQ)>=LONG) regused[iy]=1;
+ if(c==PUSH&&(p->q1.flags&(REG|DREFOBJ))!=REG){
+ if(zmeqto(p->q2.val.vmax,Z1)){
+ if(regs[acc]) t=(t>2)?t:2;
+ }else if(zmeqto(p->q2.val.vmax,l2zm(2L))){
+ if(regs[acc]&®s[ix]&®s[iy]&&(CPU==6812||regs[iu])) t=(t>2)?t:2;
+ }else if(zmeqto(p->q2.val.vmax,l2zm(4L))){
+ if(regs[acc]) t=(t>2)?t:2;
+ }else{
+ /* TODO: finer check */
+ if(drel||!regsa[iu])
+ t=(t>8)?t:8;
+ else
+ t=(t>6)?t:6;
+ }
+ }
+ }
+ emit(f,"#toff=%d\n",t);
+ loff=zm2l(offset)+t;
+ function_top(f,v,loff);
+ stackoffset=notpopped=dontpop=maxpushed=0;
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_REGS;
+ for(p=fp;p;pr(f,p),p=p->next){
+ c=p->code;t=p->typf;
+ if(debug_info)
+ dwarf2_line_info(f,p);
+ short_add=0;
+ if(c==NOP) continue;
+ if(c==ALLOCREG){
+ regs[p->q1.reg]=1;
+ if(p->q1.reg==dx) regs[acc]=regs[ix]=1;
+ continue;
+ }
+ if(c==FREEREG){
+ regs[p->q1.reg]=0;
+ if(p->q1.reg==dx) regs[acc]=regs[ix]=0;
+ continue;
+ }
+ if(notpopped&&!dontpop){
+ int flag=0;
+ if(c==LABEL||c==COMPARE||c==TEST||(c>=BEQ&&c<=BRA)){
+ gen_pop(f,notpopped);
+ notpopped=0;
+ }
+ }
+ if(c==LABEL) {cc=0;emit(f,"%s%d:\n",labprefix,t);continue;}
+ if(c>=BEQ&&c<=BGT&&t==exit_label) need_return=1;
+ if(c==BRA){
+ if(p->typf==exit_label&&!have_frame){
+ emit(f,"\t%s\n",ret);
+ }else{
+ if(t==exit_label) need_return=1;
+ emit(f,"\tbra\t%s%d\n",labprefix,t);
+ }
+ cc=0;continue;
+ }
+ if(c>=BEQ&&c<BRA){
+ if((lastcomp&UNSIGNED)||ISPOINTER(lastcomp))
+ emit(f,"\tb%s\t%s%d\n",uccs[c-BEQ],labprefix,t);
+ else
+ emit(f,"\tb%s\t%s%d\n",ccs[c-BEQ],labprefix,t);
+ continue;
+ }
+ if(c==MOVETOREG){
+ load_reg(f,p->z.reg,&p->q1,SHORT);
+ continue;
+ }
+ if(c==MOVEFROMREG){
+ store_reg(f,p->q1.reg,&p->z,SHORT);
+ continue;
+ }
+
+ /*if(ISFLOAT(t)) {pric2(stdout,p);ierror(0);}*/
+
+ if((t&NQ)==BIT){
+ ierror(0);
+ }
+
+ if(c==CONVERT&&ISLWORD(t)&&ISINT(t)&&ISLWORD(p->typf2)&&ISINT(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=l2zm(4L);
+ }
+
+ if((p->q2.flags®)&&ISACC(p->q2.reg)&&(c==ADD||c==MULT||c==AND||c==OR||c==XOR)){
+ obj o=p->q1;
+ p->q1=p->q2;
+ p->q2=o;
+ }
+
+ if(c==TEST){
+ lastcomp=t;
+ p->code=c=COMPARE;
+ gval.vmax=l2zm(0L);
+ p->q2.flags=KONST;
+ eval_const(&gval,MAXINT);
+ insert_const(&p->q2.val,t);
+ }
+
+ if(c==SUBPFP){
+ p->code=c=SUB;
+ p->typf=t=(UNSIGNED|INT);
+ }
+
+
+
+ if((c==ASSIGN||c==PUSH)&&zmeqto(p->q2.val.vmax,l2zm(4L))&&ISINT(t))
+ p->typf=t=LONG;
+
+ preload(f,p);
+
+ if(c==ADDI2P||c==SUBIFP){
+ if((p->typf2&NQ)!=HPOINTER){
+ if(p->q2.flags&KONST){
+ eval_const(&p->q2.val,p->typf);
+ insert_const(&p->q2.val,p->typf2);
+ p->typf=t=(UNSIGNED|SHORT);
+ }else{
+ if(ISLWORD(t)) inc_addr(&p->q2,2,t);
+ if((t&NQ)==CHAR) short_add=t;
+ p->typf=t=(UNSIGNED|SHORT);
+ }
+ }else if(ISHWORD(t)){
+ if((t&NQ)==LLONG)
+ inc_addr(&p->q2,4,t);
+ else if((t&NQ)!=LONG)
+ short_add=t;
+ p->typf=t=(UNSIGNED|LONG);
+ }
+ p->code=c=(c==ADDI2P)?ADD:SUB;
+ }
+
+ if(c==COMPARE&&ISLWORD(t)){
+ IC *branch=p->next;
+ int r;
+ while(branch&&branch->code==FREEREG) branch=branch->next;
+ if(!branch) ierror(0);
+ c=branch->code;
+ if(c<BEQ||c>BGT) ierror(0);
+ if(!regs[ix])
+ r=ix;
+ else
+ r=get_reg(f,p,INT);
+
+ if(c==BEQ||c==BNE){
+ inc_addr(&p->q1,0,t);
+ inc_addr(&p->q2,0,t);
+ load_reg(f,r,&p->q1,INT);
+ emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+ emit_obj(f,&p->q2,INT);
+ emit(f,"\n");
+ if(pushed_acc) emit(f,SPULLD);
+ emit(f,"\tbne\t%s%d\n",labprefix,c==BEQ?++label:branch->typf);
+ if(pushed_acc) emit(f,SPUSHD);
+ inc_addr(&p->q1,2,t);
+ inc_addr(&p->q2,2,t);
+ load_reg(f,r,&p->q1,INT);
+ emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+ emit_obj(f,&p->q2,INT);
+ emit(f,"\n");
+ pr(f,p);
+ if(c==BEQ){
+ emit(f,"\tbeq\t%s%d\n",labprefix,branch->typf);
+ emit(f,"%s%d:\n",labprefix,label);
+ }else
+ emit(f,"\tbne\t%s%d\n",labprefix,branch->typf);
+ }else{
+ inc_addr(&p->q1,0,t);
+ inc_addr(&p->q2,0,t);
+ load_reg(f,r,&p->q1,INT);
+ emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+ emit_obj(f,&p->q2,INT);
+ emit(f,"\n");
+ label++;
+ if(pushed_acc) emit(f,SPULLD);
+ if(t&UNSIGNED){
+ if(c==BLT||c==BGT)
+ emit(f,"\tb%s\t%s%d\n",(c==BLT)?"lo":"hi",labprefix,branch->typf);
+ else
+ emit(f,"\tb%s\t%s%d\n",(c==BGE)?"lo":"hi",labprefix,label);
+ }else{
+ if(c==BLT||c==BGT)
+ emit(f,"\tb%s\t%s%d\n",(c==BLT)?"lt":"gt",labprefix,branch->typf);
+ else
+ emit(f,"\tb%s\t%s%d\n",(c==BGE)?"lt":"gt",labprefix,label);
+ }
+ emit(f,"\tbne\t%s%d\n",labprefix,(c==BLT||c==BGT)?label:branch->typf);
+ if(pushed_acc) emit(f,SPUSHD);
+ inc_addr(&p->q1,2,t);
+ inc_addr(&p->q2,2,t);
+ load_reg(f,r,&p->q1,INT);
+ emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+ emit_obj(f,&p->q2,INT);
+ emit(f,"\n");
+ pr(f,p);
+ emit(f,"\tb%s\t%s%d\n",uccs[c-BEQ],labprefix,branch->typf);
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ branch->code=NOP;
+ continue;
+ }
+
+ if(ISLWORD(t)&&(c==LSHIFT||c==RSHIFT)){
+ int cnt=-1000,i,r=0;
+ int px=0,py=0,pa=0;
+ if(isconst(q2)){
+ eval_const(&p->q2.val,p->typf2);
+ cnt=(int)zm2l(vmax);
+ if(cnt==1&&compare_objects(&p->q1,&p->z)){
+ if(c==LSHIFT)
+ emit(f,"\tlsl\t");
+ else
+ emit(f,"\t%s\t",(t&UNSIGNED)?"lsr":"asr");
+ inc_addr(&p->z,c==LSHIFT?3:0,t);
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror");
+ inc_addr(&p->z,c==LSHIFT?-1:1,t);
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror");
+ inc_addr(&p->z,c==LSHIFT?-1:1,t);
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror");
+ inc_addr(&p->z,c==LSHIFT?-1:1,t);
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ continue;
+ }
+ }
+ inc_addr(&p->q1,2,t);
+ inc_addr(&p->z,2,t);
+
+ if(ISRACC(q2)||(regs[acc]&&!scratchreg(acc,p))){
+ emit(f,SPUSHD);
+ push(2);
+ pa=1;
+ }
+
+ if(cnt<0||(optsize&&cnt>1)||(cnt>3&&!optspeed)){
+ if(regs[ix]&&!scratchreg(ix,p)) {px=1;emit(f,SPUSH("x"));push(2);}
+ if(regs[iy]&&!scratchreg(iy,p)) {py=1;emit(f,SPUSH("y"));push(2);}
+ }
+
+ if(!compare_objects(&p->q1,&p->z)){
+ load_reg(f,acc,&p->q1,INT);
+ store_reg(f,acc,&p->z,INT);
+ }
+ inc_addr(&p->q1,-2,t);
+ inc_addr(&p->z,-2,t);
+ load_reg(f,acc,&p->q1,INT);
+ if(cnt<0||(optsize&&cnt>1)||(cnt>3&&!optspeed)){
+ if((p->q2.flags®)&&p->q2.reg==ix){
+ if((p->z.flags®)&&p->z.reg==iy) ierror(0);
+ }else
+ load_addr(f,ix,&p->z);
+ if(ISRACC(q2)){
+ if(scratchreg(acc,p)&&(px+py==0)){
+ emit(f,SPULL("y"));
+ pop(2);pa=0;
+ }else
+ emit(f,"\tldy\t%d,%s\n",(px+py)*2,regnames[sp]);
+ }else
+ load_reg(f,iy,&p->q2,p->typf2); /*TODO: types!=INT?? */
+ if((p->q2.flags®)&&p->q2.reg==ix)
+ load_addr(f,ix,&p->z);
+ if(c==LSHIFT)
+ emit(f,"\t%s\t%s__lsll\n",jsrinst,idprefix);
+ else
+ emit(f,"\t%s\t%s__%s\n",jsrinst,idprefix,(t&UNSIGNED)?"lsrl":"asrl");
+ if(py) {emit(f,SPULL("y"));pop(2);}
+ if(px) {emit(f,SPULL("x"));pop(2);}
+ }else{
+ inc_addr(&p->z,c==LSHIFT?3:2,t);
+ for(i=0;i<cnt;i++){
+ if(c==LSHIFT){
+ emit(f,"\tlsl\t");
+ emit_obj(f,&p->z,CHAR);
+ emit(f,"\n");
+ inc_addr(&p->z,-1,t);
+ emit(f,"\trol\t");
+ emit_obj(f,&p->z,CHAR);
+ emit(f,"\n");
+ inc_addr(&p->z,1,t);
+ emit(f,"\trolb\n");
+ emit(f,"\trola\n");
+ }else{
+ emit(f,"\t%s\n",(t&UNSIGNED)?"lsra":"asra");
+ emit(f,"\trorb\n");
+ emit(f,"\tror\t");
+ emit_obj(f,&p->z,CHAR);
+ emit(f,"\n");
+ inc_addr(&p->z,1,t);
+ emit(f,"\tror\t");
+ emit_obj(f,&p->z,CHAR);
+ emit(f,"\n");
+ inc_addr(&p->z,-1,t);
+ }
+ }
+ inc_addr(&p->z,c==LSHIFT?-3:-2,t);
+ store_reg(f,acc,&p->z,INT);
+ }
+ if(pa) {emit(f,SPULLD);pop(2);}
+ continue;
+ }
+
+ if(ISLWORD(t)&&c!=GETRETURN&&c!=SETRETURN&&c!=COMPARE&&c!=CONVERT&&c!=ADDRESS){
+ if(c==PUSH&&isreg(q1)&&p->q1.reg==dx){
+ if(CPU==6812){
+ emit(f,"\tpshd\n");
+ emit(f,"\tpshx\n");
+ }else{
+ /*emit(f,"\tpshs\ta,b,x\n");*/
+ emit(f,"\tpshs\tb,a\n");
+ emit(f,"\tpshs\tx\n");
+ }
+ dontpop += 4;
+ push(4);
+ continue;
+ }
+ if(c==ASSIGN&&isreg(q1)&&p->q1.reg==dx){
+ inc_addr(&p->z,2,t);
+ store_reg(f,ix,&p->z,INT);
+ inc_addr(&p->z,-2,t);
+ store_reg(f,acc,&p->z,INT);
+ continue;
+ }
+ if(c==ASSIGN&&isreg(z)&&p->z.reg==dx){
+ inc_addr(&p->q1,2,t);
+ load_reg(f,ix,&p->q1,INT);
+ inc_addr(&p->q1,-2,t);
+ load_reg(f,acc,&p->q1,INT);
+ continue;
+ }
+ if(c==PUSH){
+ if(regs[acc]) emit(f,"\tstd\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+ }else
+ get_acc(f,p);
+ /*TODO: acc in IC, constants */
+ inc_addr(&p->q1,2,t);
+ if(c==MINUS){
+ if(CPU!=6812&&!optsize)
+ emit(f,"\tldd\t#0\n");
+ else
+ emit(f,"\tclra\n\tclrb\n");
+ }else
+ load_reg(f,acc,&p->q1,INT);
+ if(c==ADD||c==SUB){
+ inc_addr(&p->q2,2,t);
+ emit(f,"\t%s\t",c==ADD?"addd":"subd");
+ emit_obj(f,&p->q2,INT);
+ emit(f,"\n");
+ }else if(c==ASSIGN||c==PUSH){
+ }else if(c==MINUS){
+ emit(f,"\tsubd\t");
+ emit_obj(f,&p->q1,INT);
+ emit(f,"\n");
+ }else if(c==KOMPLEMENT){
+ emit(f,"\tcoma\n");
+ emit(f,"\tcomb\n");
+ }else{
+ if(c==AND)
+ emit(f,"\tandb\t");
+ else if(c==OR)
+ emit(f,"\tor%sb\t",CPU==6812?"a":"");
+ else if(c==XOR)
+ emit(f,"\teorb\t");
+ inc_addr(&p->q2,3,t);
+ emit_obj(f,&p->q2,CHAR);
+ emit(f,"\n");
+ if(c==AND)
+ emit(f,"\tanda\t");
+ else if(c==OR)
+ emit(f,"\tor%sa\t",CPU==6812?"a":"");
+ else if(c==XOR)
+ emit(f,"\teora\t");
+ inc_addr(&p->q2,-1,t);
+ emit_obj(f,&p->q2,CHAR);
+ emit(f,"\n");
+ }
+ if(c==PUSH){
+ if(CPU==6812)
+ emit(f,"\tpshd\n");
+ else
+ emit(f,"\tpshs\tb,a\n");
+ push(2);dontpop+=2;
+ }else{
+ inc_addr(&p->z,2,t);
+ store_reg(f,acc,&p->z,INT);
+ }
+ inc_addr(&p->q1,-2,t);
+ if(c==MINUS)
+ emit(f,"\tldd\t#0\n");
+ else
+ load_reg(f,acc,&p->q1,INT);
+ if(c==ADD)
+ emit(f,"\tadcb\t");
+ else if(c==SUB)
+ emit(f,"\tsbcb\t");
+ else if(c==AND)
+ emit(f,"\tandb\t");
+ else if(c==OR)
+ emit(f,"\tor%sb\t",CPU==6812?"a":"");
+ else if(c==XOR)
+ emit(f,"\teorb\t");
+ else if(c==KOMPLEMENT)
+ emit(f,"\tcomb\n");
+ else if(c==MINUS){
+ inc_addr(&p->q1,1,t);
+ emit(f,"\tsbcb\t");
+ emit_obj(f,&p->q1,CHAR);
+ emit(f,"\n");
+ }
+ if(p->q2.flags){
+ inc_addr(&p->q2,-1,t);
+ emit_obj(f,&p->q2,CHAR);
+ emit(f,"\n");
+ }
+ if(c==ADD)
+ emit(f,"\tadca\t");
+ else if(c==SUB)
+ emit(f,"\tsbca\t");
+ else if(c==AND)
+ emit(f,"\tanda\t");
+ else if(c==OR)
+ emit(f,"\tor%sa\t",CPU==6812?"a":"");
+ else if(c==XOR)
+ emit(f,"\teora\t");
+ else if(c==KOMPLEMENT)
+ emit(f,"\tcoma\n");
+ else if(c==MINUS){
+ inc_addr(&p->q1,-1,t);
+ emit(f,"\tsbca\t");
+ emit_obj(f,&p->q1,CHAR);
+ emit(f,"\n");
+ }
+ if(p->q2.flags){
+ inc_addr(&p->q2,-1,t);
+ emit_obj(f,&p->q2,CHAR);
+ emit(f,"\n");
+ }
+ if(c==PUSH){
+ if(CPU==6812)
+ emit(f,"\tpshd\n");
+ else
+ emit(f,"\tpshs\tb,a\n");
+ push(2);dontpop+=2;
+ if(regs[acc]) emit(f,"\tldd\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+ }else{
+ inc_addr(&p->z,-2,t);
+ store_reg(f,acc,&p->z,INT);
+ }
+ continue;
+ }
+
+
+ if(c==COMPARE){
+ int vadr;
+ if(drel&&(p->q1.flags&VARADR)&&!ISFUNC(p->q1.v->vtyp->flags)) vadr=1;
+ else if(drel&&(p->q2.flags&VARADR)&&!ISFUNC(p->q2.v->vtyp->flags)) vadr=2;
+ else if(pcrel&&(p->q1.flags&VARADR)&&ISFUNC(p->q1.v->vtyp->flags)) vadr=1;
+ else if(pcrel&&(p->q2.flags&VARADR)&&ISFUNC(p->q2.v->vtyp->flags)) vadr=2;
+ else vadr=0;
+ if(vadr!=1&&(vadr==2||isconst(q1)||ISRACC(q2))){
+ struct IC *p2;
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ p2=p->next;
+ while(p2&&p2->code==FREEREG) p2=p2->next;
+ if(!p2||p2->code<BEQ||p2->code>BGT) ierror(0);
+ if(p2->code==BLT) p2->code=BGT;
+ else if(p2->code==BGT) p2->code=BLT;
+ else if(p2->code==BLE) p2->code=BGE;
+ else if(p2->code==BGE) p2->code=BLE;
+ }
+ /* case with two relative addresses */
+ if(drel&&(p->q2.flags&VARADR)&&!ISFUNC(p->q2.v->vtyp->flags)) skip_rel=1;
+ if(pcrel&&(p->q2.flags&VARADR)&&ISFUNC(p->q2.v->vtyp->flags)) skip_rel=1;
+ }
+#if 0
+ /* TODO: fix cc */
+ if(c==COMPARE&&isconst(q2)){
+ eval_const(&p->q2.val,t);
+ if(ISNULL()){
+ if(cc&&(cc_t&NU)==(t&NU)&&compare_objects(cc,&p->q1)){
+ lastcomp=t;continue;
+ }
+ }
+ }
+#endif
+
+ if(!short_add)
+ switch_IC(p);
+
+ if(c==CONVERT){
+ int to=p->typf2&NU;
+ if(to==INT) to=SHORT;
+ if(to==(UNSIGNED|INT)||to==NPOINTER) to=(UNSIGNED|SHORT);
+ if(to==FPOINTER||to==HPOINTER) to=(UNSIGNED|LONG);
+ if((t&NU)==INT) t=SHORT;
+ if((t&NU)==(UNSIGNED|INT)||(t&NU)==NPOINTER) t=(UNSIGNED|SHORT);
+ if((t&NQ)==FPOINTER||(t&NQ)==HPOINTER) t=(UNSIGNED|LONG);
+ /*if((t&NQ)>=LONG||(to&NQ)>=LONG) ierror(0);*/
+ if((to&NQ)<=LONG&&(t&NQ)<=LONG){
+ if((to&NQ)<(t&NQ)){
+ if(ISLWORD(t)){
+ get_acc(f,p);
+ load_reg(f,acc,&p->q1,to);
+ if((to&NU)==CHAR)
+ emit(f,SEX);
+ else if((to&NU)==(UNSIGNED|CHAR))
+ emit(f,"\tclra\n");
+ inc_addr(&p->z,2,t);
+ store_reg(f,acc,&p->z,INT);
+ inc_addr(&p->z,-2,t);
+ if(to&UNSIGNED){
+ emit(f,"\tclra\n\tclrb\n");
+ }else{
+ if(CPU==6812)
+ emit(f,"\texg\ta,b\n");
+ else
+ emit(f,"\ttfr\ta,b\n");
+ emit(f,SEX);
+ emit(f,"\ttfr\ta,b\n");
+ }
+ store_reg(f,acc,&p->z,INT);
+ continue;
+ }
+ /*emit(f,"#conv RACC=%d, regs=%d scratch=%d\n",(int)ISRACC(z),regs[acc],scratchreg(acc,p));*/
+ if(!ISRACC(z))
+ get_acc(f,p);
+ load_reg(f,acc,&p->q1,to);
+ if(to&UNSIGNED)
+ emit(f,"\tclra\n");
+ else
+ emit(f,SEX);
+ store_reg(f,acc,&p->z,t);
+ cc=&p->z;cc_t=t;
+ continue;
+ }else if((to&NQ)>(t&NQ)){
+ if(!ISRACC(z)&&!ISRACC(q1))
+ get_acc(f,p);
+ if(ISLWORD(to))
+ inc_addr(&p->q1,2,to);
+ load_reg(f,acc,&p->q1,to);
+ store_reg(f,acc,&p->z,t);
+ continue;
+ }else{
+ c=ASSIGN;
+ p->q2.val.vmax=sizetab[t&NQ];
+ }
+ }
+ }
+ if(c==KOMPLEMENT){
+ cc=0;
+ if(compare_objects(&p->q1,&p->z)&&!isreg(q1)&&(p->q1.flags&(REG|DREFOBJ))!=DREFOBJ&&(!p->q1.am||p->q1.am->flags!=ACC_IND)){
+ emit(f,"\tcom\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ if(ISHWORD(t)){
+ mobj=p->z;
+ inc_addr(&mobj,1,t);
+ emit(f,"\tcom\t");
+ emit_obj(f,&mobj,INT);
+ emit(f,"\n");
+ }
+ continue;
+ }
+ if((!isreg(z)||p->z.reg!=acc)&®s[acc]&&!scratchreg(acc,p))
+ get_acc(f,p);
+ load_reg(f,acc,&p->q1,t);
+ emit(f,"\tcoma\n\tcomb\n");
+ store_reg(f,acc,&p->z,t);
+ continue;
+ }
+ if(c==MINUS){
+ if((!isreg(z)||p->z.reg!=acc)&®s[acc]&&!scratchreg(acc,p))
+ get_acc(f,p);
+ if(isreg(q1)){
+ load_reg(f,acc,&p->q1,t);
+ emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+ }else{
+ if(CPU!=6812&&!optsize)
+ emit(f,"\tldd\t#0\n");
+ else
+ emit(f,"\tclra\n\tclrb\n");
+ emit(f,"\tsubd\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ cc=&p->z;cc_t=t;
+ store_reg(f,acc,&p->z,t);
+ continue;
+ }
+ if(c==SETRETURN){
+ if(isreg(q1)&&p->q1.reg==p->z.reg) continue;
+ if(p->z.reg){
+ if(ISLWORD(t)){
+ inc_addr(&p->q1,0,t);
+ load_reg(f,ix,&p->q1,INT);
+ BSET(regs_modified,ix);
+ inc_addr(&p->q1,2,t);
+ }
+ load_reg(f,acc,&p->q1,t);
+ BSET(regs_modified,acc);
+
+ }
+ continue;
+ }
+ if(c==GETRETURN){
+ if(isreg(z)&&p->z.reg==p->q1.reg) continue;
+ if(p->q1.reg){
+ if(ISLWORD(t)){
+ store_reg(f,ix,&p->z,INT);
+ BSET(regs_modified,ix);
+ inc_addr(&p->z,2,t);
+ }
+ store_reg(f,acc,&p->z,(t&NQ)==CHAR?t:INT);
+ }
+ continue;
+ }
+ if(c==CALL){
+ int reg,jmp=0;
+ cc=0;
+ if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS;
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+ long of=va_offset(v)+loff+2;
+ emit(f,"\ttfr\t%s,d\n",regnames[sp]);
+ if(of) emit(f,"\taddd\t#%ld\n",of);
+ continue;
+ }
+ if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ jmp=1;
+ }else{
+ if(stackoffset==0&&!have_frame&&!strcmp(ret,"rts")){
+ struct IC *p2;
+ jmp=1;
+ for(p2=p->next;p2;p2=p2->next){
+ if(p2->code!=FREEREG&&p2->code!=ALLOCREG&&p2->code!=LABEL){
+ jmp=0;break;
+ }
+ }
+ }
+ if(p->q1.flags&DREFOBJ){
+ /*FIXME: test this*/
+ if(jmp)
+ emit(f,"\tjmp\t");
+ else
+ emit(f,"\tjsr\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }else{
+ if(jmp){
+ emit(f,"\t%s\t",jmpinst); /*emit(f,"\tbra\t");*/
+ /*if(!need_return) ret=0;*/ /*TODO: works with optimizer? */
+ }else{
+ emit(f,"\t%s\t",jsrinst); /*emit(f,"\tbsr\t");*/
+ }
+ if(pcrel){
+ pcrel=0;
+ emit_obj(f,&p->q1,t);
+ pcrel=1;
+ }else
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ }
+ if(stack_valid){
+ int i;
+ if(p->call_cnt<=0){
+ err_ic=p;if(f) error(320);
+ stack_valid=0;
+ }
+ for(i=0;stack_valid&&i<p->call_cnt;i++){
+ if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_STACK)){
+ /*FIXME: size of return addr depends on mode */
+ if(!jmp) push(2);
+ callee_push(zm2l(p->call_list[i].v->fi->stack1));
+ if(!jmp) pop(2);
+ }else{
+ err_ic=p;if(f) error(317,p->call_list[i].v->identifier);
+ stack_valid=0;
+ }
+ }
+ }
+ if(!zmeqto(l2zm(0L),p->q2.val.vmax)){
+ notpopped+=zm2l(p->q2.val.vmax);
+ dontpop-=zm2l(p->q2.val.vmax);
+ if(!(g_flags[2]&USEDFLAG)&&stackoffset==-notpopped){
+ /* Entfernen der Parameter verzoegern */
+ }else{
+ gen_pop(f,zm2l(p->q2.val.vmax));
+ notpopped-=zm2l(p->q2.val.vmax);
+ }
+ }
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax);
+ if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+ unsigned long size;int qr=0,zr=0,cr=0,px=0,py=0,pu=0,pd=0,lq=0,lz=0;
+ size=zm2l(p->q2.val.vmax);
+ if(c==ASSIGN){
+ if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ISIDX(p->z.reg)){
+ zr=p->z.reg;lz=1;
+ }
+ }
+ if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ISIDX(p->q1.reg)&&p->q1.reg!=zr){
+ qr=p->q1.reg;lq=1;
+ }
+ if(!qr){
+ if(zr==ix) qr=iy;
+ else if(zr==iy||zr==iu) qr=ix;
+ else{qr=ix;zr=iy;}
+ }else if(!zr){
+ if(qr==ix) zr=iy; else zr=ix;
+ }
+ if(CPU!=6812){
+ if(qr!=iu&&zr!=iu) cr=iu;
+ if(qr!=ix&&zr!=ix) cr=ix;
+ if(qr!=iy&&zr!=iy) cr=iy;
+ if(!cr) ierror(0);
+ }
+ if(c==PUSH){
+ emit(f,"\tleas\t%ld,%s\n",SGN16(-size),regnames[sp]);
+ push(size);
+ }
+ if(CPU!=6812&&(drel||!regused[iu]||(regs[iu]&&!scratchreg(iu,p)))){
+ if(c==PUSH)
+ emit(f,"\tstu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
+ else{
+ emit(f,SPUSH("u"));
+ push(2);
+ }
+ pu=1;
+ }
+ if(!regused[iy]||(regs[iy]&&!scratchreg(iy,p))){
+ if(c==PUSH)
+ emit(f,"\tsty\t%ld,%s\n",loff-roff-4-stackoffset,regnames[sp]);
+ else{
+ emit(f,SPUSH("y"));
+ push(2);
+ }
+ py=1;
+ }
+ if(regs[ix]&&!scratchreg(ix,p)){
+ if(c==PUSH)
+ emit(f,"\tstx\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+ else{
+ emit(f,SPUSH("x"));
+ push(2);
+ }
+ px=1;
+ }
+ if(!lq) load_addr(f,qr,&p->q1);
+ if(c==PUSH)
+ emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[zr]);
+ else
+ if(!lz) load_addr(f,zr,&p->z);
+ if(size<=6||(size<=16&&!optsize)){
+ if(CPU!=6812){
+ if(!scratchreg(acc,p)){
+ if(c==PUSH)
+ emit(f,"\tstd\t%ld,%s\n",loff-roff-6-stackoffset,regnames[sp]);
+ else{
+ emit(f,SPUSHD);
+ push(2);
+ }
+ pd=2;
+ }
+ }
+ while(size>2){
+ if(CPU==6812)
+ emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+ else
+ emit(f,"\tldd\t,%s++\n\tstd\t,%s++\n",regnames[qr],regnames[zr]);
+ size-=2;
+ }
+ if(CPU==6812)
+ emit(f,"\tmov%c\t0,%s,0,%s\n",size==2?'w':'b',regnames[qr],regnames[zr]);
+ else
+ emit(f,"\tld%c\t,%s\n\tst%c\t,%s\n",size==2?'d':'b',regnames[qr],size==2?'d':'b',regnames[zr]);
+ }else{
+ int l=++label,cnt=(int)(optsize?(CPU==6812?size:(size/2)):size/8);
+ if(regs[acc]&&!scratchreg(acc,p)){
+ if(c==PUSH)
+ emit(f,"\tst%c\t%ld,%s\n",(CPU!=6812&&cnt<=255)?'b':'d',loff-roff-6-stackoffset,regnames[sp]);
+ else{
+ if(CPU!=6812&&cnt<=255){
+ emit(f,SPUSH("b"));
+ push(1);
+ }else{
+ emit(f,SPUSHD);
+ push(2);
+ }
+ }
+ pd=(CPU!=6812&&cnt<=255)?1:2;
+ }
+ if(CPU!=6812&&cnt<=255)
+ emit(f,"\tldb\t#%lu\n",cnt);
+ else
+ emit(f,"\tldd\t#%lu\n",cnt);
+ cc=0;
+#if 0
+ if(CPU!=6812&&((!regsa[iu]&®s[iu])||drel)){
+ if(c==PUSH){
+ emit(f,"\tstu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
+ }else{
+ emit(f,SPUSH("u"));push(2);
+ }
+ }
+#endif
+ emit(f,"%s%d:\n",labprefix,l);
+ if(CPU==6812){
+ if(optsize){
+ emit(f,"\tmovb\t1,%s+,1,%s+\n",regnames[qr],regnames[zr]);
+ size=0;
+ }else{
+ emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+ emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+ emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+ emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+ size=size&7;
+ }
+ emit(f,"\tdbne\td,%s%d\n",labprefix,l);
+ }else{
+ if(optsize){
+ emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+ size&=1;
+ }else{
+ emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+ emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+ emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+ emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+ size&=7;
+ }
+ if(cnt<=255)
+ emit(f,"\tdecb\n");
+ else
+ emit(f,"\tsubd\t#1\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,l);
+ }
+#if 0
+ if(CPU!=6812&&((!regsa[iu]&®s[iu])||drel)){
+ if(c==PUSH){
+ emit(f,"\tldu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
+ }else{
+ emit(f,SPULL("u"));pop(2);
+ }
+ }
+#endif
+ while(size>=2){
+ if(CPU==6812)
+ emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+ else
+ emit(f,"\tldd\t,%s++\n\tstd\t,%s++\n",regnames[qr],regnames[zr]);
+ size-=2;
+ }
+ if(size){
+ if(CPU==6812)
+ emit(f,"\tmovb\t0,%s,0,%s\n",regnames[qr],regnames[zr]);
+ else
+ emit(f,"\tldb\t,%s\n\tstb\t,%s\n",regnames[qr],regnames[zr]);
+ }
+ }
+ if(pd){
+ if(c==PUSH)
+ emit(f,"\tld%c\t%ld,%s\n",(pd==1)?'b':'d',loff-roff-6-stackoffset,regnames[sp]);
+ else{
+ if(pd==1){
+ emit(f,SPULL("b"));
+ pop(1);
+ }else{
+ emit(f,SPULLD);
+ pop(2);
+ }
+ }
+ }
+ if(px){
+ if(c==PUSH)
+ emit(f,"\tldx\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+ else{
+ emit(f,SPULL("x"));
+ pop(2);
+ }
+ }
+ if(py){
+ if(c==PUSH)
+ emit(f,"\tldy\t%ld,%s\n",loff-roff-4-stackoffset,regnames[sp]);
+ else{
+ emit(f,SPULL("y"));
+ pop(2);
+ }
+ }
+ if(pu){
+ if(c==PUSH)
+ emit(f,"\tldu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
+ else{
+ emit(f,SPULL("u"));
+ pop(2);
+ }
+ }
+ continue;
+ }
+ if(!ISSCALAR(t)) t=zmeqto(p->q2.val.vmax,l2zm(1L))?CHAR:INT;
+ if((t&NQ)==CHAR&&!zmeqto(p->q2.val.vmax,l2zm(1L))) t=INT;
+ if(mov_op(&p->q1)&&(c==PUSH||mov_op(&p->z))){
+ emit(f,"\tmov%c\t",ISHWORD(t)?'w':'b');
+ emit_obj(f,&p->q1,t);
+ if(c==ASSIGN){
+ emit(f,",");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ }else{
+ emit(f,",%d,-%s\n",ISHWORD(t)?2:1,regnames[sp]);
+ push(ISHWORD(t)?2:1);
+ }
+ continue;
+ }
+ if(((regs[acc]&®s[ix])||(t&NQ)==CHAR)&&(p->q1.flags&KONST)&&!isreg(z)){
+ eval_const(&p->q1.val,t);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&((p->z.flags&(REG|DREFOBJ))!=DREFOBJ||(t&NQ)==CHAR)&&(!p->z.am||p->z.am->flags!=ACC_IND||(t&NQ)==CHAR)){
+ emit(f,"\tclr\t");
+ if(c==ASSIGN){
+ emit_obj(f,&p->z,t);emit(f,"\n");
+ }else{
+ emit(f,CPU==6812?"1,-sp\n":",-s\n");
+ push(1);
+ }
+ if(!ISHWORD(t)) continue;
+ emit(f,"\tclr\t");
+ if(c==ASSIGN){
+ mobj=p->z;
+ inc_addr(&mobj,1,t);
+ emit_obj(f,&mobj,t);emit(f,"\n");
+ }else{
+ emit(f,CPU==6812?"1,-sp\n":",-s\n");
+ push(1);
+ }
+ continue;
+ }
+
+ }
+ if(c==PUSH){
+ int st=0;
+ if(isreg(q1)){
+ reg=p->q1.reg;
+ }else{
+ if((t&NQ)==CHAR||!regs[acc]||scratchreg(acc,p)) reg=acc;
+ else if(!regs[ix]||scratchreg(ix,p)) reg=ix;
+ else if(regused[iy]&&(!regs[iy]||scratchreg(iy,p))) reg=iy;
+ else if(regused[iu]&&!drel&&CPU!=6812&&(!regs[iu]||scratchreg(iu,p))) reg=iu;
+ else reg=acc;
+ if(regs[reg]&&!scratchreg(reg,p)){
+ st=1;
+ emit(f,"\tst%s\t%ld,%s\n",regnames[reg],(long)loff-roff-2-stackoffset,regnames[sp]);
+ }
+ load_reg(f,reg,&p->q1,t);
+ }
+ if((t&NQ)==CHAR)
+ emit(f,SPUSH("b"));
+ else if(reg==ix)
+ emit(f,SPUSH("x"));
+ else if(reg==iy)
+ emit(f,SPUSH("y"));
+ else if(reg==iu)
+ emit(f,SPUSH("u"));
+ else
+ emit(f,SPUSHD);
+ push(zm2l(p->q2.val.vmax));
+ if(st)
+ emit(f,"\tld%s\t%ld,%s\n",regnames[reg],(long)loff-roff-2-stackoffset,regnames[sp]);
+ continue;
+ }
+ if(c==ASSIGN){
+ if(isreg(q1)&&isreg(z)){
+ if(p->q1.reg!=p->z.reg)
+ emit(f,"\ttfr\t%s,%s\n",regnames[p->q1.reg],regnames[p->z.reg]);
+ }else if(isreg(q1)){
+ store_reg(f,p->q1.reg,&p->z,t);
+ }else if(isreg(z)){
+ load_reg(f,p->z.reg,&p->q1,t);
+ }else{
+ reg=get_reg(f,p,t);
+ load_reg(f,reg,&p->q1,t);
+ store_reg(f,reg,&p->z,t);
+ }
+ continue;
+ }
+ ierror(0);
+ }
+ if(c==ADDRESS){
+ int px=0;
+ if(isreg(z)){
+ reg=p->z.reg;
+ }else if(!regs[ix]){
+ reg=ix;
+ }else if(!regs[iy]){
+ reg=iy;
+ }else{
+ /*FIXME: test if x used in q1 */
+ px=1;
+ emit(f,SPUSH("x"));
+ reg=ix;
+ push(2);
+ }
+ load_addr(f,reg,&p->q1);
+ if(!(p->z.flags®)||p->z.reg!=reg)
+ store_reg(f,reg,&p->z,p->typf2);
+ if(px){
+ emit(f,SPULL("x"));
+ pop(2);
+ }
+ continue;
+ }
+
+ if((c==MULT||c==DIV||(c==MOD&&(p->typf&UNSIGNED)))&&isconst(q2)){
+ long ln;
+ eval_const(&p->q2.val,t);
+ if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+ if((ln=pof2(vumax))&&ln<5){
+ if(c==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ c=p->code=c=AND;
+ }else{
+ vmax=l2zm(ln-1);
+ if(c==DIV) p->code=c=RSHIFT; else p->code=c=LSHIFT;
+ }
+ c=p->code;
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ if(c==AND){
+ insert_const(&p->q2.val,t);
+ }else{
+ insert_const(&p->q2.val,t);
+ p->typf2=INT;
+ }
+ }
+ }
+ }
+ if(c==MOD||c==DIV){
+ ierror(0);
+ continue;
+ }
+
+
+ if((c==ADD||c==SUB)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&(p->q1.flags&(REG|DREFOBJ))!=REG&&(p->q1.flags&(REG|DREFOBJ))!=DREFOBJ&&!p->q1.am&&!p->z.am&&compare_objects(&p->q1,&p->z)){
+ eval_const(&p->q2.val,t);
+ if(c==SUB) vmax=zmsub(Z0,vmax);
+ if((t&NQ)==CHAR&&zmeqto(vmax,Z1)){
+ emit(f,"\tinc\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ continue;
+ }else if((t&NQ)==CHAR&&zmeqto(vmax,l2zm(-1L))){
+ emit(f,"\tdec\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ continue;
+ }else if(((t&NQ)==SHORT||(t&NQ)==INT)&&zmeqto(vmax,l2zm(1L))){
+ inc_addr(&p->z,1,t);
+ emit(f,"\tinc\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,++label);
+ inc_addr(&p->z,-1,t);
+ emit(f,"\tinc\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ continue;
+ }else if(regs[acc]&&((t&NQ)==SHORT||(t&NQ)==INT)&&zmeqto(vmax,l2zm(-1L))){
+ inc_addr(&p->z,1,t);
+ emit(f,"\ttst\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,++label);
+ inc_addr(&p->z,-1,t);
+ emit(f,"\tdec\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ inc_addr(&p->z,1,t);
+ emit(f,"\tdec\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ continue;
+ }
+ }
+
+ if((c>=LSHIFT&&c<=MOD)||c==ADDI2P||c==SUBIFP||c==SUBPFP||(c>=OR&&c<=AND)||c==COMPARE){
+ char *s;
+ /*FIXME: nicht immer besser*/
+ if(ISLWORD(t)&&c==LSHIFT&&isconst(q2)){
+ eval_const(&p->q2.val,t);
+ if(zm2l(vmax)==1){
+ p->code=c=ADD;
+ p->q2=p->q1;
+ }
+ }
+ if((c==ADD||c==ADDI2P||c==MULT||(c>=OR&&c<=AND))&&isreg(q2)&&!isreg(q1)&&!short_add){
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ }
+ if((c==ADD||c==MULT||(c>=OR&&c<=AND))&&isreg(q2)&&p->q2.reg==acc&&!short_add){
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ }
+ if(c==MULT||c==MOD){
+ if((!isreg(z)||p->z.reg!=acc)&®s[acc]&&!scratchreg(acc,p))
+ get_acc(f,p);
+ reg=acc;
+ /*FIXME: y bzw. x-Register*/
+ }else if(c==LSHIFT||c==RSHIFT||c==AND||c==OR||c==XOR){
+ if((!isreg(z)||p->z.reg!=acc)&®s[acc]&&!scratchreg(acc,p))
+ get_acc(f,p);
+ reg=acc;
+ }else if(c==DIV){
+ reg=ix;
+ ierror(0);
+ }else if(isreg(z)){
+ reg=p->z.reg;
+ }else if(isreg(q1)&&(c==COMPARE||scratchreg(p->q1.reg,p))){
+ reg=p->q1.reg;
+ }else{
+ if(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==COMPARE){
+ if(ISRACC(q2))
+ reg=acc;
+ else
+ reg=get_reg(f,p,t);
+ }else{
+ get_acc(f,p);
+ reg=acc;
+ }
+ }
+ if(c==ADD||c==ADDI2P||c==SUB||c==SUBIFP){
+ int opdone=0;
+ if(isreg(q1)){
+ if(ISIDX(reg)&&ISIDX(p->q1.reg)&&isconst(q2)){
+ eval_const(&p->q2.val,short_add?short_add:q2typ(p));
+ if(CPU==6812&&p->q1.reg==reg&&zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL))){
+ emit(f,"\t%s%s\n",c==SUB?"de":"in",regnames[reg]);
+ /*FIXME: condition-codes for bne/beq could be used */
+ }else{
+ emit(f,"\tlea%s\t%ld,%s\n",regnames[reg],c==SUB?SGN16(-zm2l(vmax)):SGN16(zm2l(vmax)),regnames[p->q1.reg]);
+ }
+ opdone=1;
+ }else if((c==ADD||c==ADDI2P)&&ISIDX(reg)&&ISIDX(p->q1.reg)&&ISRACC(q2)){
+ emit(f,"\tlea%s\t%s,%s\n",regnames[reg],((t&NQ)==CHAR||(short_add&NQ)==CHAR)?"b":"d",regnames[p->q1.reg]);
+ opdone=1;
+ }else if((c==ADD||c==ADDI2P)&&ISIDX(reg)&&ISACC(p->q1.reg)&&ISRIDX(q2)){
+ emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[p->q2.reg]);
+ opdone=1;
+ }else if((c==ADD||c==ADDI2P)&&p->q1.reg==acc&&ISIDX(reg)&&!short_add){
+ load_reg(f,reg,&p->q2,t);
+ emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[reg]);
+ opdone=1;
+ }else if((c==ADD||c==ADDI2P)&&p->q1.reg==acc&&ISIDX(reg)&&(short_add&NU)==(UNSIGNED|CHAR)&&scratchreg(acc,p)){
+ emit(f,"\taddb\t");
+ emit_obj(f,&p->q2,short_add);
+ emit(f,"\n");
+ emit(f,"\tadca\t#0\n");
+ emit(f,"\ttfr\td,y\n");
+ opdone=1;
+ }else if((c==ADD||c==ADDI2P)&&ISACC(p->q1.reg)&&ISRACC(z)&&isreg(q2)&&ISIDX(p->q2.reg)){
+ if(!scratchreg(p->q2.reg,p)) emit(f,"\texg\t%s,%s\n",regnames[acc],regnames[p->q2.reg]);
+ emit(f,"\tlea%s\t%s,%s\n",regnames[p->q2.reg],regnames[acc],regnames[p->q2.reg]);
+ emit(f,"\texg\t%s,%s\n",regnames[acc],regnames[p->q2.reg]);
+ opdone=1;
+ }else if(p->q1.reg!=reg){
+ if(c==ADD||c==ADDI2P||!ISRACC(q2))
+ emit(f,"\ttfr\t%s,%s\n",regnames[p->q1.reg],regnames[reg]);
+ }
+ }else if(short_add&&c==SUB&®==acc&&!(short_add&UNSIGNED)){
+ load_reg(f,reg,&p->q2,short_add);
+ emit(f,"\tclra\n");
+ emit(f,"\tnegb\n");
+ emit(f,"\tsbca\t#0\n");
+ emit(f,"\taddd\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ store_reg(f,reg,&p->z,ztyp(p));
+ continue;
+ }else if(short_add&&c==ADD&®==acc){
+ load_reg(f,reg,&p->q2,short_add);
+ if(short_add&UNSIGNED)
+ emit(f,"\tclra\n");
+ else
+ emit(f,SEX);
+ emit(f,"\taddd\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ store_reg(f,reg,&p->z,ztyp(p));
+ continue;
+ }else{
+ if(!ISRACC(q2))
+ load_reg(f,reg,&p->q1,q1typ(p));
+ }
+ if(!opdone){
+ if(reg==acc){
+ if(ISRACC(q2)){
+ if(!ISRACC(z)) get_acc(f,p);
+ if(c==ADD||c==ADDI2P){
+ if(short_add){
+ if(short_add&UNSIGNED)
+ emit(f,"\tclra\n");
+ else
+ emit(f,SEX);
+ emit(f,"\taddd\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }else{
+ if(CPU==6812)
+ emit(f,"\tasld\n"); /* only cases with q1=q2=acc should remain */
+ else{
+ emit(f,"\taslb\n");
+ if((t&NQ)!=CHAR)
+ emit(f,"\trola\n");
+ }
+ }
+ }else{
+ if(short_add){
+ if(short_add&UNSIGNED)
+ emit(f,"\tld%sa\t#255\n",(CPU==6812)?"a":"");
+ else{
+ emit(f,SEX);
+ emit(f,"\tnega\n");
+ }
+ emit(f,"\tnegb\n\tsbca\t#0\n");
+ }else if((t&NQ)!=CHAR){
+ emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+ }else{
+ emit(f,"\tnegb\n");
+ }
+
+ if(ISRIDX(q1)){
+ emit(f,"\t%s%s\n",CPU==6812?"psh":"pshs\t",regnames[p->q1.reg]);
+ emit(f,"\taddd\t%s\n",CPU==6812?"1,s+":",s++");
+ }else{
+ emit(f,"\taddd\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ }
+ }else{
+ if(ISRIDX(q2)){
+ if(CPU==6812)
+ emit(f,"\tpsh%s\n",regnames[p->q2.reg]);
+ else
+ emit(f,"\tpshs\t%s\n",regnames[p->q2.reg]);
+ push(2);pop(2);
+ if(CPU==6812)
+ emit(f,"\t%sd\t2,%s+\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]);
+ else
+ emit(f,"\t%sd\t,%s++\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]);
+ }else{
+ emit(f,"\t%s%s\t",(c==ADD||c==ADDI2P)?"add":"sub",(short_add||(t&NQ)==CHAR)?"b":"d");
+ emit_obj(f,&p->q2,short_add?short_add:t);emit(f,"\n");
+ if(short_add){
+ if(short_add&UNSIGNED)
+ emit(f,"\t%s\t#0\n",c==ADD?"adca":"sbca");
+ else
+ ierror(0);
+ }
+ if(drel&&(p->q2.flags&VARADR)){
+ if(CPU==6812) ierror(0);
+ emit(f,"\tpshs\t%s\n",regnames[iu]);push(2);
+ emit(f,"\t%sd\t,%s++\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]);
+ pop(2);
+ }
+ }
+ }
+ cc=&p->z;cc_t=t;
+ }else{
+ if(isconst(q2)){
+ long l;
+ eval_const(&p->q2.val,short_add?short_add:t);
+ l=zm2l(vmax);
+ if(c==SUB) l=-l;
+ /*FIXME: condition-codes for bne/beq could be used */
+ if(l==1&®==ix&&CPU==6812){
+ emit(f,"\tinx\n");
+ }else if(l==1&®==iy&&CPU==6812){
+ emit(f,"\tiny\n");
+ }else if(l==-1&®==ix&&CPU==6812){
+ emit(f,"\tdex\n");
+ }else if(l==-1&®==iy&&CPU==6812){
+ emit(f,"\tdey\n");
+ }else{
+ emit(f,"\tlea%s\t%ld,%s\n",regnames[reg],SGN16(l),regnames[reg]);
+ }
+ }else{
+ if(c!=ADD&&c!=ADDI2P){
+ if(!ISRACC(q2)){
+ if(!scratchreg(acc,p))
+ get_acc(f,p);
+ load_reg(f,acc,&p->q2,t);
+ if((t&NQ)!=CHAR){
+ emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+ }else{
+ emit(f,"\tnegb\n");
+ }
+ /*load_reg(f,reg,&p->q1,t);*/
+ }else{
+ get_acc(f,p);
+ load_reg(f,reg,&p->q1,t);
+ if((t&NQ)==CHAR)
+ emit(f,"\tnegb\n");
+ else
+ emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+ }
+ }else if(!ISRACC(q2)){
+ get_acc(f,p);
+ if(short_add){
+ load_reg(f,acc,&p->q2,short_add);
+ if(short_add&UNSIGNED){
+ if(reg==ix){
+ emit(f,"\tabx\n");
+ store_reg(f,reg,&p->z,ztyp(p));
+ continue;
+ }else{
+ emit(f,"\tclra\n");
+ }
+ }else
+ t=CHAR;
+ }else
+ load_reg(f,acc,&p->q2,t);
+ }else{
+ load_reg(f,reg,&p->q1,t);
+ if(short_add&UNSIGNED)
+ emit(f,"\tclra\n");
+ emit(f,"\tlea%s\t%s,%s\n",regnames[reg],((t&NU)==CHAR||(short_add&NU)==CHAR)?"b":"d",regnames[reg]);
+ store_reg(f,reg,&p->z,ztyp(p));
+ continue;
+ }
+ emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[reg]);
+ }
+ }
+ }
+ store_reg(f,reg,&p->z,ztyp(p));
+ continue;
+ }
+ if(c!=LSHIFT&&c!=RSHIFT)
+ load_reg(f,reg,&p->q1,t);
+ if(c==MULT){
+ if(CPU==6812){
+ int py=0;
+ if(reg!=acc) ierror(reg);
+ if(!ISRY(q2)&®s[iy]){
+ emit(f,"\tpshy\n");
+ push(2);
+ py=1;
+ }
+ load_reg(f,iy,&p->q2,t);
+ emit(f,"\temul\n");
+ if(py){
+ emit(f,SPULL("y"));
+ pop(2);
+ }
+ store_reg(f,acc,&p->z,t);
+ continue;
+ }else
+ ierror(0);
+ }
+ if(c==LSHIFT||c==RSHIFT){
+ if(isconst(q2)){
+ int l,oldl;
+ load_reg(f,acc,&p->q1,t);
+ eval_const(&p->q2.val,t);
+ oldl=l=zm2l(vmax);
+ if(l>=16){
+ if(CPU!=6812&&!optsize)
+ emit(f,"\tldd\t#0\n");
+ else
+ emit(f,"\tclra\n\tclrb\n");
+ l=0;
+ }
+ if(l>=8){
+ if(c==LSHIFT)
+ emit(f,"\t%s\n\tclrb\n",(CPU==6812)?"tba":"tfr\tb,a");
+ else{
+ if(t&UNSIGNED)
+ emit(f,"\ttfr\ta,b\n\tclra\n");
+ else{
+ emit(f,"\ttfr\ta,b\n");
+ emit(f,SEX);
+ }
+ }
+ l-=8;
+ }
+ while(l--){
+ if(c==RSHIFT){
+ if(t&UNSIGNED){
+ if((t&NQ)==CHAR)
+ emit(f,"\tlsrb\n");
+ else
+ emit(f,CPU!=6812?"\tlsra\n\trorb\n":"\tlsrd\n");
+ }else{
+ if(oldl>8||(t&NQ)==CHAR)
+ emit(f,"\tasrb\n");
+ else
+ emit(f,"\tasra\n\trorb\n");
+ }
+ }else{
+ if((t&NQ)==CHAR)
+ emit(f,"\taslb\n");
+ else
+ emit(f,CPU!=6812?"\taslb\n\trola\n":"\tasld\n");
+ }
+ }
+ }else{
+ int px;char *s;
+ if(regs[ix]&&!scratchreg(ix,p)&&(!isreg(z)||p->z.reg!=ix)){
+ emit(f,SPUSH("x"));
+ push(2);px=1;
+ }else
+ px=0;
+
+ /* tell if X or D are ready for shifting */
+ int xdone = 0;
+ int ddone = 0;
+
+ /* free X if q1 is in X */
+ if (ISRX(q1)) {
+ ddone = 1;
+ if (ISRACC(q2)) {
+ xdone = 1;
+ if (ISCHAR(p->typf2)) emit(f, EXTEND(p->typf2));
+ emit(f, "\texg\tx,d\n");
+ }
+ else {
+ emit(f, "\ttfr\tx,d\n");
+ }
+ }
+ /* load q2 in X if not done yet */
+ if (!xdone) {
+ if (ISLWORD(p->typf2)) {
+ /* q2 is 32bit, it is in memory, we take the lower 16bit */
+ inc_addr(&p->q2, 2, p->typf2);
+ load_reg(f, ix, &p->q2, INT);
+ }
+ else if (ISHWORD(p->typf2)) {
+ /* q2 is 16bit, load it directly in X */
+ load_reg(f, ix, &p->q2, INT);
+ }
+ else {
+ /* q2 is 8bit, we must extend it in D */
+ /* if D is busy with q1, save q1 in X */
+ if (ddone || ISRACC(q1)) {
+ if (ISCHAR(t)) emit(f, EXTEND(t));
+ emit(f, "\ttfr\td,x\n");
+ load_reg(f, acc, &p->q2, CHAR);
+ emit(f, EXTEND(p->typf2));
+ emit(f, "\texg\tx,d\n");
+ ddone = 1;
+ }
+ else {
+ load_reg(f, acc, &p->q2, CHAR);
+ emit(f, EXTEND(p->typf2));
+ emit(f, "\ttfr\td,x\n");
+ }
+ }
+ }
+ /* load q1 in D if not done yet */
+ if (!ddone) {
+ load_reg(f, acc, &p->q1, t);
+ if (ISCHAR(t)) emit(f, EXTEND(t));
+ }
+
+
+ if(c==LSHIFT) s="lsl";
+ else if(t&UNSIGNED) s="lsr";
+ else s="asr";
+ emit(f,"\t.global\t%s__%s\n",idprefix,s);
+ emit(f,"\t%s\t%s__%s\n",jsrinst,idprefix,s);
+ if(px){
+ emit(f,SPULL("x"));
+ /*emit(f,"\tpul%s\n",regnames[ix]);*/
+ pop(2);
+ }
+ }
+ cc=0;
+ store_reg(f,acc,&p->z,t);
+ continue;
+ }
+ if(c>=OR&&c<=AND){
+ s=logicals[c-OR];
+ if(p->q2.am&&p->q2.am->flags==ACC_IND){
+ mobj=p->q1;p->q1=p->q2;p->q2=mobj;
+ }
+ if(p->q2.flags&KONST){
+ unsigned long l,h;
+ eval_const(&p->q2.val,t);
+ l=zum2ul(vumax);
+ if((t&NQ)!=CHAR){
+ h=(l>>8)&255;
+ if(c==AND&&h==0)
+ emit(f,"\tclra\n");
+ else if(c==XOR&&h==255)
+ emit(f,"\tcoma\n");
+ else if((c==AND&&h!=255)||(c==OR&&h!=0)||(c==XOR&&h!=0))
+ emit(f,"\t%sa\t#%lu\n",s,h);
+ }
+ h=l&255;
+ if(c==AND&&h==0)
+ emit(f,"\tclrb\n");
+ else if(c==XOR&&h==255)
+ emit(f,"\tcomb\n");
+ else if((c==AND&&h!=255)||(c==OR&&h!=0)||(c==XOR&&h!=0))
+ emit(f,"\t%sb\t#%lu\n",s,h);
+ }else{
+ if(isreg(q2)){
+ if(p->q2.reg==acc){
+ if(c==XOR){
+ emit(f,"\tclrb\n");
+ if((t&NQ)!=CHAR) emit(f,"\tclra\n");
+ }
+ }else{
+ if((t&NQ)==CHAR){
+ emit(f,SPUSH("a"));
+ push(1);
+ emit(f,"\t%sa\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]);
+ pop(1);
+ }else{
+ emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[p->q2.reg]);
+ push(2);
+ emit(f,"\t%sa\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]);
+ emit(f,"\t%sb\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]);
+ pop(2);
+ }
+ }
+ }else if((p->q2.flags&(REG|DREFOBJ))==DREFOBJ&&(t&NQ)!=CHAR){
+ int xr=0;
+ if(!regs[ix]) xr=ix;
+ else if(!regs[iy]) xr=iy;
+ else{
+ xr=ix;
+ emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[xr]);
+ push(2);
+
+ }
+ BSET(regs_modified,xr);
+ load_addr(f,xr,&p->q2);
+ if((t&NQ)==CHAR)
+ emit(f,"\t%sb\t0,%s\n",s,regnames[xr]);
+ else{
+ emit(f,"\t%sa\t0,%s\n",s,regnames[xr]);
+ emit(f,"\t%sb\t1,%s\n",s,regnames[xr]);
+ }
+ if(regs[ix]&&xr==ix){
+ emit(f,SPULL("x"));
+ pop(2);
+ }
+ }else{
+ emit(f,"\t%sb\t",s);
+ if((t&NQ)!=CHAR) inc_addr(&p->q2,1,t);
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ if((t&NQ)!=CHAR){
+ inc_addr(&p->q2,-1,t);
+ emit(f,"\t%sa\t",s);
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+ }
+ }
+ cc=0;
+ store_reg(f,reg,&p->z,t);
+ continue;
+ }else if(c==COMPARE){
+ lastcomp=t;
+ if(isreg(q2)){
+ emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[p->q2.reg]);
+ push(2);
+ }
+ if(reg==acc){
+ if((t&NQ)==CHAR)
+ emit(f,"\tcmpb\t");
+ else
+ emit(f,SCMP("d"));
+ }else if(reg==ix){
+ emit(f,SCMP("x"));
+ }else if(reg==iy){
+ emit(f,SCMP("y"));
+ }else if(reg==iu){
+ emit(f,SCMP("u"));
+ }else
+ ierror(0);
+ if(isreg(q2)){
+ if(CPU==6812)
+ emit(f,"2,%s+\n",regnames[sp]);
+ else
+ emit(f,",%s++\n",regnames[sp]);
+ pop(2);
+ }else{
+ emit_obj(f,&p->q2,t);emit(f,"\n");
+ }
+ continue;
+ }
+ ierror(0);
+ }
+ pric2(stdout,p);
+ ierror(0);
+ }
+ if(notpopped){
+ gen_pop(f,notpopped);
+ notpopped=0;
+ }
+ function_bottom(f,v,loff);
+ if(debug_info){
+ emit(f,"%s%d:\n",labprefix,++label);
+ dwarf2_function(f,v,label);
+ if(f) section=-1;
+ }
+}
+
+int shortcut(int c,int t)
+{
+ if(c==COMPARE||c==ADD||c==SUB||c==AND||c==OR||c==XOR) return 1;
+ if((c==LSHIFT||c==RSHIFT)&&ISCHWORD(t&NQ)) return 1;
+ return 0;
+}
+
+void cleanup_cg(FILE *f)
+{
+ struct fpconstlist *p;
+ unsigned char *ip;
+ if(f&&stack_check)
+ emit(f,"\t.global\t%s__stack_check\n",idprefix);
+ while(p=firstfpc){
+ if(f){
+ if(section!=RODATA){
+ emit(f,rodataname);if(f) section=RODATA;
+ }
+ emit(f,"%s%d\n\t%s\t",labprefix,p->label,dct[LONG]);
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ if((p->typ&NQ)==DOUBLE||(p->typ&NQ)==LDOUBLE){
+ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ emit(f,"\n");
+ }
+ firstfpc=p->next;
+ free(p);
+ }
+}
+
+int reg_parm(struct reg_handle *p,struct Typ *t,int mode,struct Typ *fkt)
+{
+ if(p->gpr) return 0;
+ if(ISSCALAR(t->flags)&&!ISFLOAT(t->flags)&&!ISLWORD(t->flags)){
+ p->gpr=1;
+ return acc;
+ }
+ return 0;
+}
+
+void insert_const(union atyps *p,int t)
+/* Traegt Konstante in entprechendes Feld ein. */
+{
+ if(!p) ierror(0);
+ t&=NU;
+ if(t==BIT) {if(zmeqto(zc2zm(vchar),l2zm(0L))) p->vchar=zm2zc(l2zm(0L)); else p->vchar=zm2zc(l2zm(1L));return;}
+ if(t==CHAR) {p->vchar=vchar;return;}
+ if(t==SHORT) {p->vshort=vshort;return;}
+ if(t==INT) {p->vint=vint;return;}
+ if(t==LONG) {p->vlong=vlong;return;}
+ if(t==LLONG) {p->vllong=vllong;return;}
+ if(t==MAXINT) {p->vmax=vmax;return;}
+ if(t==(UNSIGNED|BIT)) {if(zumeqto(zuc2zum(vuchar),ul2zum(0UL))) p->vuchar=zum2zuc(ul2zum(0UL)); else p->vuchar=zum2zuc(ul2zum(1UL));return;}
+ if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+ if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+ if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+ if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+ if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+ if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+ if(t==FLOAT) {p->vfloat=vfloat;return;}
+ if(t==DOUBLE) {p->vdouble=vdouble;return;}
+ if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+ if(t==NPOINTER) {p->vuint=vuint;return;}
+ if(t==FPOINTER||t==HPOINTER) {p->vulong=vulong;return;}
+}
+void eval_const(union atyps *p,int t)
+/* Weist bestimmten globalen Variablen Wert einer CEXPR zu. */
+{
+ int f=t&NQ;
+ if(!p) ierror(0);
+ if(f==MAXINT||(f>=BIT&&f<=LLONG)){
+ if(!(t&UNSIGNED)){
+ if(f==BIT){
+ if(zmeqto(zc2zm(p->vchar),l2zm(0L))) vmax=l2zm(0L); else vmax=l2zm(1L);
+ }else if(f==CHAR) vmax=zc2zm(p->vchar);
+ else if(f==SHORT)vmax=zs2zm(p->vshort);
+ else if(f==INT) vmax=zi2zm(p->vint);
+ else if(f==LONG) vmax=zl2zm(p->vlong);
+ else if(f==LLONG) vmax=zll2zm(p->vllong);
+ else if(f==MAXINT) vmax=p->vmax;
+ else ierror(0);
+ vumax=zm2zum(vmax);
+ vldouble=zm2zld(vmax);
+ }else{
+ if(f==BIT){
+ if(zumeqto(zuc2zum(p->vuchar),ul2zum(0UL))) vumax=ul2zum(0UL); else vumax=ul2zum(1UL);
+ }else if(f==CHAR) vumax=zuc2zum(p->vuchar);
+ else if(f==SHORT)vumax=zus2zum(p->vushort);
+ else if(f==INT) vumax=zui2zum(p->vuint);
+ else if(f==LONG) vumax=zul2zum(p->vulong);
+ else if(f==LLONG) vumax=zull2zum(p->vullong);
+ else if(f==MAXINT) vumax=p->vumax;
+ else ierror(0);
+ vmax=zum2zm(vumax);
+ vldouble=zum2zld(vumax);
+ }
+ }else{
+ if(ISPOINTER(f)){
+ if(f==NPOINTER)
+ vumax=zui2zum(p->vuint);
+ else
+ vumax=zul2zum(p->vulong);
+ vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+ }else{
+ if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+ else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+ else vldouble=p->vldouble;
+ vmax=zld2zm(vldouble);
+ vumax=zld2zum(vldouble);
+ }
+ }
+ vfloat=zld2zf(vldouble);
+ vdouble=zld2zd(vldouble);
+ vuchar=zum2zuc(vumax);
+ vushort=zum2zus(vumax);
+ vuint=zum2zui(vumax);
+ vulong=zum2zul(vumax);
+ vullong=zum2zull(vumax);
+ vchar=zm2zc(vmax);
+ vshort=zm2zs(vmax);
+ vint=zm2zi(vmax);
+ vlong=zm2zl(vmax);
+ vllong=zm2zll(vmax);
+}
+void printval(FILE *f,union atyps *p,int t)
+/* Gibt atyps aus. */
+{
+ t&=NU;
+ if(t==BIT){vmax=zc2zm(p->vchar);fprintf(f,"B%d",!zmeqto(vmax,l2zm(0L)));}
+ if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);fprintf(f,"UB%d",!zumeqto(vmax,ul2zum(0UL)));}
+ if(t==CHAR){vmax=zc2zm(p->vchar);printzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+ if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+ if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+ if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+ if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+ if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+ if(t==(UNSIGNED|INT)||t==NPOINTER){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+ if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+ if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+ if(t==MAXINT) printzm(f,p->vmax);
+ if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax);
+}
+void emitval(FILE *f,union atyps *p,int t)
+{
+ t&=NU;
+ if((t&NQ)==NPOINTER) t=(UNSIGNED|INT);
+ if(t==BIT){vmax=zc2zm(p->vchar);emit(f,"%d",!zmeqto(vmax,l2zm(0L)));}
+ if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);emit(f,"%d",!zumeqto(vmax,ul2zum(0UL)));}
+ if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+ if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+ if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+ if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+ if(t==LDOUBLE){emitzld(f,p->vldouble);}
+ if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+ if(t==(UNSIGNED|INT)||t==NPOINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+ if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+ if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+ if(t==MAXINT) emitzm(f,p->vmax);
+ if(t==(UNSIGNED|MAXINT)) emitzum(f,p->vumax);
+}
+
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+ char *attr;
+ while(p){
+ if(ISPOINTER(p->flags)){
+ p->flags=((p->flags&~NU)|POINTER_TYPE(p->next));
+ if(attr=p->next->attr){
+ if(strstr(attr,STR_NEAR))
+ p->flags=((p->flags&~NU)|NPOINTER);
+ if(strstr(attr,STR_FAR))
+ p->flags=((p->flags&~NU)|FPOINTER);
+ if(strstr(attr,STR_HUGE))
+ p->flags=((p->flags&~NU)|HPOINTER);
+ }
+ }
+ if(ISINT(p->flags)&&(attr=p->attr)&&strstr(attr,"bit"))
+ p->flags=((p->flags&~NU)|BIT);
+ p=p->next;
+ }
+}
+
+void init_db(FILE *f)
+{
+ dwarf2_setup(sizetab[HPOINTER],".byte",".2byte",".4byte",".4byte",labprefix,idprefix,".section");
+ dwarf2_print_comp_unit_header(f);
+}
+void cleanup_db(FILE *f)
+{
+ dwarf2_cleanup(f);
+ if(f) section=-1;
+}
diff --git a/machines/hc12/machine.dt b/machines/hc12/machine.dt
new file mode 100755
index 0000000..7c090f1
--- /dev/null
+++ b/machines/hc12/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S32BIEEEBE
+S32BIEEEBE
+S16BUbE S16BULE
+
+
diff --git a/machines/hc12/machine.h b/machines/hc12/machine.h
new file mode 100755
index 0000000..096e608
--- /dev/null
+++ b/machines/hc12/machine.h
@@ -0,0 +1,191 @@
+/* Example of a code-generator for Motorola 68hc12 16bit microcontrollers.*/
+
+#include "dt.h"
+
+/* We have extended types! What we have to do to support them: */
+/* - #define HAVE_EXT_TYPES
+ - #undef all standard types
+ - #define all standard types plus new types
+ - write eval_const and insert_const
+ - write typedefs for zmax and zumax
+ - write typname[]
+ - write conv_typ()
+ - optionally #define ISPOINTER, ISARITH, ISINT etc.
+ - optionally #define HAVE_TGT_PRINTVAL and write printval
+ - optionally #define POINTER_TYPE
+ - optionally #define HAVE_TGT_FALIGN and write falign
+ - optionally #define HAVE_TGT_SZOF and write szof
+ - optionally add functions for attribute-handling
+*/
+#define HAVE_EXT_TYPES 1
+
+#define HAVE_TGT_PRINTVAL
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef MAXINT
+#undef MAX_TYPE
+
+#define BIT 1
+#define CHAR 2
+#define SHORT 3
+#define INT 4
+#define LONG 5
+#define LLONG 6
+#define FLOAT 7
+#define DOUBLE 8
+#define LDOUBLE 9
+#define VOID 10
+#define NPOINTER 11
+#define FPOINTER 12
+#define HPOINTER 13
+#define ARRAY 14
+#define STRUCT 15
+#define UNION 16
+#define ENUM 17
+#define FUNKT 18
+
+#define MAXINT 19
+
+#define MAX_TYPE MAXINT
+
+#define POINTER_TYPE(x) pointer_type(x)
+extern int pointer_type();
+#define ISPOINTER(x) ((x&NQ)>=NPOINTER&&(x&NQ)<=HPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=BIT&&(x&NQ)<=HPOINTER)
+#define ISINT(x) ((x&NQ)>=BIT&&(x&NQ)<=LLONG)
+#define PTRDIFF_T(x) ((x)==HPOINTER?LONG:INT)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+ zchar vchar;
+ zuchar vuchar;
+ zshort vshort;
+ zushort vushort;
+ zint vint;
+ zuint vuint;
+ zlong vlong;
+ zulong vulong;
+ zllong vllong;
+ zullong vullong;
+ zmax vmax;
+ zumax vumax;
+ zfloat vfloat;
+ zdouble vdouble;
+ zldouble vldouble;
+};
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Not used in this code-generrator. */
+struct AddressingMode{
+ int flags;
+ int base;
+ long offset;
+ struct Var *v;
+};
+
+/* This type will be added to every IC. Can be used by the cg. */
+#define HAVE_EXT_IC 1
+struct ext_ic {
+ int flags;
+ int r;
+ long offset;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR 6
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 20
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+extern int MINADDI2P;
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 1
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 0
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+extern int switchsubs;
+#define SWITCHSUBS switchsubs
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+#define HAVE_REGPARMS 1
+
+struct reg_handle {
+ int gpr;
+};
+
+/* We use unsigned int as size_t rather than unsigned long which */
+/* is the default setting. */
+#define HAVE_INT_SIZET 1
+
+/* We have register pairs. */
+#define HAVE_REGPAIRS 1
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+#define HAVE_TARGET_RALLOC 1
+#define cost_load_reg(r,v) 4
+#define cost_save_reg(r,v) 4
+#define cost_move_reg(i,j) 2
+#define cost_pushpop_reg(r) 2
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/* We have asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES 1
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+/* We prefer BNE rather than BGT. */
+#define HAVE_WANTBNE 1
+
+#define HAVE_POF2OPT 1
+
+/* Use char for return of comparison libcalls */
+#define LIBCALL_CMPTYPE CHAR
diff --git a/machines/i386/machine.c b/machines/i386/machine.c
new file mode 100755
index 0000000..68c553c
--- /dev/null
+++ b/machines/i386/machine.c
@@ -0,0 +1,2048 @@
+
+/* Code generator for Intel 80386 or higher. */
+
+#include "supp.h"
+#include "vbc.h" /* nicht schoen, aber ... */
+
+static char FILE_[]=__FILE__;
+
+#include "dwarf2.c"
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for i386 V0.7a (c) in 1996-2006 by Volker Barthelmann";
+
+/* Commandline-flags the code-generator accepts */
+int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,
+ 0,0,0,0,
+ 0};
+char *g_flags_name[MAXGF]={"cpu","fpu","no-delayed-popping","const-in-data",
+ "merge-constants","elf","longalign","safe-fp",
+ "use-framepointer"};
+union ppi g_flags_val[MAXGF];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","char","short","bshort","int","bint",
+ "long","blong","long long","blong long",
+ "float","bfloat","double","bdouble",
+ "long double","blong double","void",
+ "pointer","bpointer",
+ "array","struct","union","enum","function"};
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT of the target machine. */
+zmax char_bit;
+
+/* Sizes of all elementary types in bytes. */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. */
+char *regnames[MAXR+1]={"noreg","%eax","%ecx","%edx","%ebx",
+ "%esi","%edi","%ebp","%esp",
+ "%st(0)","%st(1)","%st(2)","%st(3)",
+ "%st(4)","%st(5)","%st(6)","%st(7)",
+ "%eax/%edx","%esi/%edi"};
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* Type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1]={0,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0};
+
+
+/****************************************/
+/* Some private data and functions. */
+/****************************************/
+
+#define USEFP (g_flags[8]&USEDFLAG)
+
+static long malign[MAX_TYPE+1]= {1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,1,1,1,2,2};
+static long msizetab[MAX_TYPE+1]={0,1,2,2,4,4,4,4,8,8,4,4,8,8,8,8,0,4,4,0,0,0,4,0};
+
+#define ISBE(x) (((x)&NQ)==BPOINTER||(((x)&NQ)>=BSHORT&&((x)&NQ)<=BLDOUBLE&&((x)&1)))
+#define LETYPE(x) ((x)-1)
+
+struct Typ ltyp={LONG},ldbl={DOUBLE};
+
+#define DATA 0
+#define BSS 1
+#define CODE 2
+
+static char *marray[]={"__I386__","__X86__",
+ "__bigendian=__attr(\"bigendian\")",
+ "__littleendian=__attr(\"littleendian\")",
+ 0};
+
+static int section=-1,newobj;
+static char *codename="\t.text\n",*dataname="\t.data\n",*bssname="";
+static const int ax=1,cx=2,dx=3,bx=4,si=5,di=6,bp=7,sp=8,axdx=17,sidi=18;
+static char x_t[]={'?','b','w','w','l','l','l','l','?','?','s','s','l','l','l','l','v','l','l','a','s','u','e','f'};
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+#define isvaddr(x) ((p->x.flags&(VARADR|DREFOBJ))==VARADR)
+#define isvconst(x) (isconst(x)||isvaddr(x))
+
+static long loff,stackoffset,notpopped,dontpop,maxpushed,stack;
+
+static char *ccs[]={"z","nz","l","ge","le","g","mp"};
+static char *ccu[]={"z","nz","b","ae","be","a","mp"};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"sal","sar","add","sub","imul","div","mod"};
+static char *farithmetics[]={"f?","f?","fadd","fsub","fmul","fdiv","fsubr","fdivr"};
+static char *dct[]={"","byte","short","short","long","long",
+ "long","long","long","long","long","long","long","long",
+ "long","long","long","long","long","long"};
+
+static int pushedsize,pushorder=2;
+static int fst[8];
+static int cxl,dil,sil;
+static char *idprefix="",*labprefix="l";
+
+static struct fpconstlist {
+ struct fpconstlist *next;
+ int label,typ;
+ union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+ struct fpconstlist *p=firstfpc;
+ t&=NQ;
+ if(g_flags[4]&USEDFLAG){
+ for(p=firstfpc;p;p=p->next){
+ if(t==p->typ){
+ eval_const(&p->val,t);
+ if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return(p->label);
+ if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return(p->label);
+ if(t==LDOUBLE&&zldeqto(vldouble,o->val.vldouble)) return(p->label);
+ }
+ }
+ }
+ p=mymalloc(sizeof(struct fpconstlist));
+ p->next=firstfpc;
+ p->label=++label;
+ p->typ=t;
+ p->val=o->val;
+ firstfpc=p;
+ return p->label;
+}
+/* pushed on the stack by a callee, no pop needed */
+static void callee_push(long l)
+{
+}
+static void push(long l)
+{
+ stackoffset-=l;
+ if(stackoffset<maxpushed) maxpushed=stackoffset;
+}
+static void pop(long l)
+{
+ stackoffset+=l;
+}
+
+void title(FILE *f)
+{
+ static int done;
+ extern char *inname; /*grmpf*/
+ if(!done&&f){
+ done=1;
+ emit(f,"\t.file\t\"%s\"\n",inname);
+ }
+}
+
+static void emit_obj(FILE *f,struct obj *p,int t)
+/* Gibt Objekt auf Bildschirm aus */
+{
+ if((p->flags&(DREFOBJ|KONST))==(DREFOBJ|KONST)){
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,"(");
+ if(p->flags&VARADR) emit(f,"$");
+ if((p->flags&VAR)&&!(p->flags®)) {
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+ if(USEFP||vlas){
+ if(!zmleq(l2zm(0L),p->v->offset))
+ emit(f,"%ld(%s)",(long)(-zm2l(p->v->offset)+zm2l(p->val.vmax))+4,regnames[bp]);
+ else
+ emit(f,"%ld(%s)",(long)(zm2l(p->v->offset)+zm2l(p->val.vmax))-loff-pushedsize,regnames[bp]);
+ }else{
+ if(!zmleq(l2zm(0L),p->v->offset))
+ emit(f,"%ld(%s)",(long)(loff-zm2l(p->v->offset)+zm2l(p->val.vmax))-stackoffset+pushedsize,regnames[sp]);
+ else
+ emit(f,"%ld(%s)",(long)(zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset),regnames[sp]);
+ }
+ }else{
+ if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ }
+ }
+ if(p->flags®){
+ if(p->reg>8){
+ int i;
+ for(i=0;i<8;i++){
+ if(fst[i]==p->reg)
+ emit(f,"%s",regnames[i+9]);
+ }
+ }else{
+ t&=NQ;
+ if(t==CHAR&&!(p->flags&DREFOBJ)) emit(f,"%%%cl",regnames[p->reg][2]);
+ else if(t==SHORT&&!(p->flags&DREFOBJ)) emit(f,"%%%s",regnames[p->reg]+2);
+ else emit(f,"%s",regnames[p->reg]);
+ }
+ }
+ if(p->flags&KONST){
+ if(ISFLOAT(t)){
+ emit(f,"%s%d",labprefix,addfpconst(p,t));
+ }else{
+ emit(f,"$");emitval(f,&p->val,t&NU);
+ }
+ }
+ if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,")");
+}
+
+static char *mregname(int r,int t)
+{
+ static char s[8];
+ t&=NQ;
+ if(t==CHAR) sprintf(s,"%%%cl",regnames[r][2]);
+ else if(t==SHORT) sprintf(s,"%%%s",regnames[r]+2);
+ else sprintf(s,"%s",regnames[r]);
+ return s;
+}
+
+
+static void emit_lword(FILE *f,struct obj *o)
+{
+ if(o->flags&KONST){
+ static struct obj cobj;
+ cobj.flags=KONST;
+ eval_const(&o->val,UNSIGNED|LLONG);
+ vumax=zumand(vumax,ul2zum(0xffffffff));
+ cobj.val.vulong=zum2zul(vumax);
+ emit_obj(f,&cobj,UNSIGNED|LONG);
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ if(!reg_pair(o->reg,&rp)) ierror(0);
+ emit(f,"%s",regnames[rp.r1]);
+ }else
+ emit_obj(f,o,UNSIGNED|LONG);
+}
+
+static void emit_hword(FILE *f,struct obj *o)
+{
+ if(o->flags&KONST){
+ static struct obj cobj;
+ cobj.flags=KONST;
+ eval_const(&o->val,UNSIGNED|LLONG);
+ vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff));
+ cobj.val.vulong=zum2zul(vumax);
+ emit_obj(f,&cobj,UNSIGNED|LONG);
+ }else if(o->flags&DREFOBJ){
+ if(!(o->flags®)) ierror(0);
+ emit(f,"4(%s)",regnames[o->reg]);
+ }else if(o->flags®){
+ if(!reg_pair(o->reg,&rp)) ierror(0);
+ emit(f,"%s",regnames[rp.r2]);
+ }else{
+ o->val.vmax=zmadd(o->val.vmax,l2zm(4L));
+ emit_obj(f,o,UNSIGNED|LONG);
+ o->val.vmax=zmsub(o->val.vmax,l2zm(4L));
+ }
+}
+
+static void dwarf2_print_frame_location(FILE *f,struct Var *v)
+{
+ /*FIXME: needs a location list and correct register trabslation */
+ struct obj o;
+ o.flags=REG;
+ if(USEFP||vlas)
+ o.reg=bp;
+ else
+ o.reg=sp;
+ o.val.vmax=l2zm(0L);
+ o.v=0;
+ dwarf2_print_location(f,&o);
+}
+static int dwarf2_regnumber(int r)
+{
+ static int dwarf_regs[17]={-1,0,1,2,3,6,7,5,4,16,17,18,19,20,21,22,23};
+ return dwarf_regs[r];
+}
+static zmax dwarf2_fboffset(struct Var *v)
+{
+ if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0);
+ if(USEFP||vlas){
+ if(!zmleq(l2zm(0L),v->offset))
+ return l2zm((long)(-zm2l(v->offset))+4);
+ else
+ return l2zm((long)(zm2l(v->offset))-loff-pushedsize);
+ }else{
+ if(!zmleq(l2zm(0L),v->offset))
+ return l2zm((long)(loff-zm2l(v->offset))+pushedsize);
+ else
+ return v->offset;
+ }
+}
+static void fxch(FILE *f,int i)
+{
+ int m;
+ emit(f,"\tfxch\t%s\n",regnames[i+9]);
+ m=fst[0];fst[0]=fst[i];fst[i]=m;
+}
+static int freest(void)
+{
+ int i;
+ for(i=0;i<8;i++){
+ if(fst[i]<0) return i;
+ }
+ for(i=0;i<8;i++){
+ if(fst[i]==0) return i;
+ }
+ ierror(0);
+}
+static void fpush(FILE *f)
+{
+ int i;
+ if(fst[7]>0){
+ i=freest();
+ if(fst[i]==0) emit(f,"\tffree\t%s\n",regnames[i+9]);
+ fxch(f,i);fxch(f,7);
+ }
+ for(i=7;i>0;i--)
+ fst[i]=fst[i-1];
+ fst[0]=-1;
+}
+static void fpop(void)
+{
+ int i;
+/* if(fst[0]>0&®s[fst[0]]) ierror(0);*/
+ for(i=0;i<7;i++)
+ fst[i]=fst[i+1];
+ fst[7]=-1;
+}
+static void fload(FILE *f,struct obj *o,int t)
+{
+ emit(f,"\tfld");
+ if((o->flags&(REG|DREFOBJ))==REG) emit(f,"\t");
+ else emit(f,"%c\t",x_t[t&NQ]);
+ emit_obj(f,o,t);emit(f,"\n");
+ fpush(f);
+}
+static void fstore(FILE *f,struct obj *o,int t)
+{
+ int i;
+ if((o->flags&(REG|DREFOBJ))==REG){
+ for(i=0;i<8;i++)
+ if(fst[i]==o->reg) fst[i]=0;
+ fst[0]=o->reg;
+ }else{
+ emit(f,"\tfstp%c\t",x_t[t&NQ]);emit_obj(f,o,t);
+ fpop();emit(f,"\n");
+ }
+}
+static void prfst(FILE *f,char *s)
+{
+ int i;
+ if(DEBUG==0) return;
+ emit(f,"#\t%s\t",s);
+ for(i=0;i<8;i++){
+ if(fst[i]>=0){
+ if(fst[i]==0) emit(f,"+++ ");
+ else emit(f,"%s ",regnames[fst[i]]+3);
+ }else{
+ emit(f,"--- ");
+ }
+ }
+ emit(f,"\n");
+}
+static void finit(void)
+{
+ int i;
+ for(i=0;i<8;i++){
+ if(regs[i+9])
+ fst[i]=i+9;
+ else
+ fst[i]=-1;
+ }
+}
+static void forder(FILE *f)
+{
+ int i,m,unordered;
+ prfst(f,"forder");
+ for(i=0;i<8;i++){
+ if(fst[i]==0){emit(f,"\tffree\t%s\n",regnames[i+9]);fst[i]=-1;}
+ }
+oloop:
+ unordered=0;
+ for(i=0;i<8;i++){
+ if(fst[i]>0&&fst[i]!=i+9&®s[fst[i]]){unordered=1;break;}
+ }
+ if(!unordered) return;
+ if(fst[0]>=0&®s[fst[0]]){
+ if(fst[0]!=9){
+ fxch(f,fst[0]-9);
+ goto oloop;
+ }else{
+ fxch(f,freest());
+ }
+ }
+ for(i=1;i<8;i++){
+ if(fst[i]>=0&&fst[i]!=i+9&®s[fst[i]]&&fst[i]!=9){
+ fxch(f,i);
+ goto oloop;
+ }
+ }
+ if(regs[9]){
+ for(i=1;i<8;i++){
+ if(fst[i]==9){ fxch(f,i);return;}
+ }
+ }
+}
+static void pr(FILE *f,struct IC *p)
+{
+ int i;
+ for(;pushorder>2;pushorder>>=1){
+ for(i=1;i<=8;i++){
+ if(regs[i]&pushorder){
+ if(p->code==PUSH||p->code==CALL){
+ emit(f,"\tmovl\t%ld(%s),%s\n",loff-4-stackoffset,regnames[sp],regnames[i]);
+ }else{
+ emit(f,"\tpopl\t%s\n",regnames[i]);
+ pop(4);
+ }
+ regs[i]&=~pushorder;
+ }
+ }
+ }
+ for(i=1;i<=8;i++)
+ if(regs[i]&2) regs[i]&=~2;
+}
+static void function_top(FILE *f,struct Var *v,long offset)
+/* erzeugt Funktionskopf */
+{
+ int i;
+ if(section!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ if(USEFP||vlas)
+ emit(f,"\tpushl\t%s\n\tmovl\t%s,%s\n",regnames[bp],regnames[sp],regnames[bp]);
+ for(pushedsize=0,i=1;i<sp;i++){
+ if(regused[i]&&!regscratch[i]){
+ emit(f,"\tpushl\t%s\n",regnames[i]);
+ pushedsize+=4;
+ }
+ }
+ if(offset) emit(f,"\tsubl\t$%ld,%%esp\n",offset);
+}
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/* erzeugt Funktionsende */
+{
+ int i;
+ forder(f);
+ if(offset) emit(f,"\taddl\t$%ld,%%esp\n",offset);
+ for(i=sp-1;i>0;i--){
+ if(regused[i]&&!regscratch[i]){
+ emit(f,"\tpopl\t%s\n",regnames[i]);
+ }
+ }
+ if(USEFP||vlas) emit(f,"\tpopl\t%s\n",regnames[bp]);
+ emit(f,"\tret\n");
+ if(v->storage_class==EXTERN){
+ emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+ emit(f,"\t.size\t%s%s,.-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
+ }else{
+ emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset));
+ emit(f,"\t.size\t%s%ld,.-%s%ld\n",labprefix,zm2l(v->offset),labprefix,zm2l(v->offset));
+ }
+}
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+ if(o1->flags==o2->flags&&o1->am==o2->am){
+ if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+ if(!(o1->flags®)||o1->reg==o2->reg){
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+static int get_reg(FILE *f,struct IC *p,int type)
+{
+ int i;
+ /* If we can use a register which was already used by the compiler */
+ /* or it is a sratch register then we can use it without problems. */
+ for(i=1;i<=8;i++){
+ if(!regs[i]&&(regused[i]||regscratch[i])&®ok(i,type,0)){
+ regs[i]=2;
+ BSET(regs_modified,i);
+ return(i);
+ }
+ }
+ /* Otherwise we have to save this register. */
+ /* We may not use a register which is used in this IC. */
+ for(i=1;i<=8;i++){
+ if(regs[i]<2&®ok(i,type,0)
+ &&(!(p->q1.flags®)||p->q1.reg!=i)
+ &&(!(p->q2.flags®)||p->q2.reg!=i)
+ &&(!(p->z.flags®)||p->z.reg!=i)
+ &&(p->code!=SETRETURN||p->z.reg!=i)
+ &&(p->code!=GETRETURN||p->q1.reg!=i) ){
+
+ if(p->code==PUSH||p->code==CALL){
+ emit(f,"\tmovl\t%s,%ld(%s)\n",regnames[i],loff-4-stackoffset,regnames[sp]);
+ }else{
+ emit(f,"\tpushl\t%s\n",regnames[i]);
+ push(4);
+ }
+ /* Mark register as pushed (taking care of the order). */
+ pushorder<<=1; regs[i]|=pushorder;
+ BSET(regs_modified,i);
+ return i;
+ }
+ }
+ ierror(0);
+}
+static void move(FILE *f,struct obj *q,int qr,struct obj *z,int zr,int t)
+/* Generates code to move object q (or register qr) into object z (or */
+/* register zr). */
+{
+ t&=NQ;
+ if(q&&(q->flags&(REG|DREFOBJ))==REG) qr=q->reg;
+ if(z&&(z->flags&(REG|DREFOBJ))==REG) zr=z->reg;
+ if((t&NQ)==LLONG){
+ if(qr&&zr&&qr==zr) return;
+ emit(f,"\tmovl\t");
+ if(qr){
+ if(!reg_pair(qr,&rp)) ierror(0);
+ emit(f,"%s",regnames[rp.r1]);
+ }else
+ emit_lword(f,q);
+ emit(f,",");
+ if(zr){
+ if(!reg_pair(zr,&rp)) ierror(0);
+ emit(f,"%s",regnames[rp.r1]);
+ }else
+ emit_lword(f,z);
+ emit(f,"\n");
+ emit(f,"\tmovl\t");
+ if(qr){
+ if(!reg_pair(qr,&rp)) ierror(0);
+ emit(f,"%s",regnames[rp.r2]);
+ }else
+ emit_hword(f,q);
+ emit(f,",");
+ if(zr){
+ if(!reg_pair(zr,&rp)) ierror(0);
+ emit(f,"%s",regnames[rp.r2]);
+ }else
+ emit_hword(f,z);
+ emit(f,"\n");
+ return;
+ }
+ if(qr&&zr){
+ if(qr!=zr)
+ emit(f,"\tmovl\t%s,%s\n",regnames[qr],regnames[zr]);
+ return;
+ }
+ if(zr&&(q->flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&q->val,t);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+ emit(f,"\txorl\t%s,%s\n",regnames[zr],regnames[zr]);
+ return;
+ }
+ }
+ emit(f,"\tmov%c\t",x_t[t&NQ]);
+ if(qr){
+ emit(f,"%s",mregname(qr,t));
+ }else
+ emit_obj(f,q,t);
+ emit(f,",");
+ if(zr){
+ emit(f,"%s",mregname(zr,t));
+ }else
+ emit_obj(f,z,t);
+ emit(f,"\n");
+}
+static long pof2(zumax x)
+/* Yields log2(x)+1 oder 0. */
+{
+ zumax p;int ln=1;
+ p=ul2zum(1UL);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+
+/****************************************/
+/* End of private fata and functions. */
+/****************************************/
+
+
+int init_cg(void)
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(4L);
+ char_bit=l2zm(8L);
+ if(g_flags[6]&USEDFLAG){
+ for(i=SHORT;i<=MAX_TYPE;i++) malign[i]=4;
+ }
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+ for(i=1;i<= 8;i++) {regsize[i]=l2zm(4L);regtype[i]=<yp;}
+ for(i=9;i<=16;i++) {regsize[i]=l2zm(8L);regtype[i]=&ldbl;}
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LONG]=t_min(INT);
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=ul2zum(2147483647UL);
+ t_max[LONG]=t_max(INT);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ t_min[BSHORT]=l2zm(-32768L);
+ t_min[BINT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[BLONG]=t_min(INT);
+ t_min[BLLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_max[BSHORT]=ul2zum(32767UL);
+ t_max[BINT]=ul2zum(2147483647UL);
+ t_max[BLONG]=t_max(INT);
+ t_max[BLLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=ul2zum(4294967295UL);
+ tu_max[LONG]=t_max(UNSIGNED|INT);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[BSHORT]=ul2zum(65535UL);
+ tu_max[BINT]=ul2zum(4294967295UL);
+ tu_max[BLONG]=t_max(UNSIGNED|INT);
+ tu_max[BLLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ /* We only reserve the stack-pointer here. */
+ regsa[sp]=1;
+ if(USEFP) regsa[bp]=regscratch[bp]=1;
+ /* We need at least one free slot in the flaoting point stack */
+ regsa[16]=1;regscratch[16]=0;
+ /* Use l%d as labels and _%s as identifiers by default. If */
+ /* -elf is specified we use .l%d and %s instead. */
+ if(g_flags[5]&USEDFLAG) labprefix=".l"; else idprefix="_";
+ target_macros=marray;
+
+ declare_builtin("__mulll",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__addll",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__subll",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__andll",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__orll",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__eorll",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__negll",LLONG,LLONG,0,0,0,1,0);
+ declare_builtin("__notll",LLONG,LLONG,0,0,0,1,0);
+ declare_builtin("__lslll",LLONG,LLONG,0,INT,0,1,0);
+
+ declare_builtin("__divll",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__divull",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__modll",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__modull",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__lsrll",LLONG,LLONG,0,INT,0,1,0);
+ declare_builtin("__lsrull",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+ declare_builtin("__cmpll",INT,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__cmpull",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
+ declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
+ declare_builtin("__sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
+ declare_builtin("__uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
+ declare_builtin("__flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
+ declare_builtin("__flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);
+
+ return 1;
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+{
+ if(ISFLOAT(t->flags)) return 9;
+ if((t->flags&NQ)==LLONG) return axdx;
+ if(ISSCALAR(t->flags)) return ax;
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ if(r==axdx){
+ p->r1=ax;
+ p->r2=dx;
+ return 1;
+ }else if(r==sidi){
+ p->r1=si;
+ p->r2=di;
+ return 1;
+ }
+ return 0;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(r==0) return(0);
+ t&=NQ;
+ if(r>8&&r<axdx){
+ if(g_flags[7]&USEDFLAG) return 0;
+ if(ISFLOAT(t)) return 1;
+ else return 0;
+ }
+ if(r==axdx||r==sidi)
+ return t==LLONG;
+ if(t==CHAR&&(r==si||r==di||r==bp)) return 0;
+ if(t<=BLONG) return 1;
+ if(ISPOINTER(t)) return 1;
+ return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* In this generic 32bit RISC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op=o&NQ,tp=t&NQ,of,tf;
+ of=ISBE(op);
+ tf=ISBE(tp);
+ if(of!=tf) return 1;
+ if(of) op=LETYPE(op);
+ if(tf) tp=LETYPE(tp);
+
+ if(tp==POINTER&&op==POINTER) return 0;
+ if((t&UNSIGNED)&&(o&UNSIGNED)&&zmeqto(sizetab[tp],sizetab[op])) return 0;
+ if((tp==INT&&op==LONG)||(tp==LONG&&op==INT)) return 0;
+ if(op==tp) return 0;
+ return 1;
+}
+
+/* Return name of library function, if this node should be
+ implemented via libcall. */
+char *use_libcall(int c,int t,int t2)
+{
+ static char fname[16];
+ char *ret=0;
+
+ if(c==COMPARE){
+ if((t&NQ)==LLONG){
+ sprintf(fname,"__cmp%sll",(t&UNSIGNED)?"u":"");
+ ret=fname;
+ }
+ }else{
+ t&=NU;
+ if(c==CONVERT){
+ if(ISFLOAT(t)&&(t2&NU)==LLONG){
+ sprintf(fname,"__%cint64toflt%d",(t2&UNSIGNED)?'u':'s',(t==FLOAT)?32:64);
+ ret=fname;
+ }
+ if(ISFLOAT(t2)&&(t&NU)==LLONG){
+ sprintf(fname,"__flt%dto%cint64",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s');
+ ret=fname;
+ }
+ }
+ if((t&NQ)==LLONG){
+ if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==PMULT||(c>=EQUAL&&c<=GREATEREQ)||c==KOMPLEMENT||c==MINUS){
+ if(t==(UNSIGNED|LLONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%sull",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==LLONG){
+ sprintf(fname,"__%sll",ename[c]);
+ ret=fname;
+ }else printf("un %d\n",c);
+ }
+ }
+ }
+ return ret;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ title(f);
+ if(newobj) emit(f,"%ld\n",zm2l(size));
+ else emit(f,"\t.space\t%ld\n",zm2l(size));
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ title(f);
+ if(zm2l(align)>1) emit(f,"\t.align\t4\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;
+ title(f);
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if((v->vtyp->flags&NQ)==FUNKT) return;
+ emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset));
+ emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp)));
+ if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ if(section!=BSS)
+ emit(f,"\t.align\t4\n%s%ld:\n",labprefix,zm2l(v->offset));
+ else{
+ emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+ newobj=1;
+ }
+ }
+ if(v->storage_class==EXTERN){
+ emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+ if(v->flags&(DEFINED|TENTATIVE)){
+ emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
+ emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp)));
+ if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ if(section!=BSS)
+ emit(f,"\t.align\t4\n%s%s:\n",idprefix,v->identifier);
+ else{
+ emit(f,"\t.comm\t%s%s,",idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ title(f);
+ emit(f,"\t.%s\t",dct[t&NQ]);
+ if(!p->tree){
+ if(ISFLOAT(t)){
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+ if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE){
+ emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+ }
+ }else if((t&NQ)==LLONG){
+ zumax tmp;
+ eval_const(&p->val,t);
+ tmp=vumax;
+ vumax=zumand(vumax,ul2zum(0xffffffff));
+ gval.vulong=zum2zul(vumax);
+ emitval(f,&gval,UNSIGNED|LONG);
+ emit(f,",");
+ vumax=zumand(zumrshift(tmp,ul2zum(32UL)),ul2zum(0xffffffff));
+ gval.vulong=zum2zul(vumax);
+ emitval(f,&gval,UNSIGNED|LONG);
+ }else{
+ emitval(f,&p->val,t&NU);
+ }
+ }else{
+ int m=p->tree->o.flags;
+ p->tree->o.flags&=~VARADR;
+ emit_obj(f,&p->tree->o,t&NU);
+ p->tree->o.flags=m;
+ }
+ emit(f,"\n");newobj=0;
+}
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+{
+ int c,t,lastcomp=0,reg;
+ struct IC *m;
+ if(DEBUG&1) printf("gen_code()\n");
+ for(c=1;c<=15;c++) regs[c]=regsa[c];
+ regs[16]=0;
+ for(c=1;c<=MAXR;c++){
+ if(regsa[c]||regused[c]){
+ BSET(regs_modified,c);
+ }
+ }
+ title(f);
+ loff=((zm2l(offset)+3)/4)*4;
+ for(m=p;m;m=m->next){
+ /* do we need another stack-slot? */
+ /* could do a more precise check */
+ if((m->code==PUSH&&(m->q1.flags&(REG|DREFOBJ))==DREFOBJ)||
+ (m->code==CALL&&(m->q1.flags&DREFOBJ))||
+ (m->code==CONVERT&&!ISFLOAT(m->typf)&&ISFLOAT(m->typf2)) ){
+ loff+=4;
+ break;
+ }
+ }
+ function_top(f,v,loff);
+ stackoffset=notpopped=dontpop=0;
+ finit();
+ for(;p;pr(f,p),p=p->next){
+ c=p->code;t=p->typf;
+ if(debug_info)
+ dwarf2_line_info(f,p);
+ if(c==NOP) continue;
+ if(c==SUBPFP) c=SUB;
+ if(c==SUBIFP) c=SUB;
+ if(c==ADDI2P) c=ADD;
+ if(c==ALLOCREG){
+ regs[p->q1.reg]=1;
+ continue;
+ }
+ if(c==FREEREG){
+ if(p->q1.reg>=9){
+ for(c=0;c<8;c++)
+ if(fst[c]==p->q1.reg) fst[c]=0;
+ }
+ regs[p->q1.reg]=0;
+ continue;
+ }
+ if(notpopped&&!dontpop){
+ if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+ emit(f,"\taddl\t$%ld,%%esp\n",notpopped);
+ pop(notpopped);
+ notpopped=0;
+ }
+ }
+
+ if(c==COMPARE&&isconst(q2)&&(t&NQ)!=LLONG){
+ struct case_table *ct=calc_case_table(p,JUMP_TABLE_DENSITY);
+ if(ct&&ct->num>=JUMP_TABLE_LENGTH){
+ int r,defl,tabl=++label;
+ long l;unsigned long ul;
+ /*FIXME: we do not generate a jump-table if we do not have a
+ free register */
+ for(r=1;r<=8;r++){
+ if(!regs[r]&®scratch[r])
+ break;
+ }
+ if(r<=8){
+ BSET(regs_modified,r);
+ if(ct->next_ic->code==BRA)
+ defl=ct->next_ic->typf;
+ else
+ defl=++label;
+ if((p->q1.flags&(REG|DREFOBJ))==DREFOBJ){
+ p->q1.flags&=~DREFOBJ;
+ emit(f,"\tmovl\t");
+ emit_obj(f,&p->q1,POINTER);
+ emit(f,",%s\n",regnames[r]);
+ p->q1.flags|=(REG|DREFOBJ);
+ p->q1.reg=r;
+ }
+ emit(f,"\tmovl\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,",%s\n",regnames[r]);
+ emit(f,"\tsubl\t$");
+ if(t&UNSIGNED)
+ emitzum(f,ct->min.vumax);
+ else
+ emitzm(f,ct->min.vmax);
+ emit(f,",%s\n",regnames[r]);
+ emit(f,"\tcmpl\t$");
+ emitzum(f,ct->diff);
+ emit(f,",%s\n",regnames[r]);
+ emit(f,"\tja\t%s%d\n",labprefix,defl);
+ emit(f,"\tjmp\t*%s%d(,%s,4)\n",labprefix,tabl,regnames[r]);
+ emit(f,"\t.align\t2\n");
+ emit(f,"%s%d:\n",labprefix,tabl);
+ emit_jump_table(f,ct,"\t.long\t",labprefix,defl);
+ if(ct->next_ic->code!=BRA){
+ emit(f,"%s%d:\n",labprefix,defl);
+ p=ct->next_ic->prev;
+ }else
+ p=ct->next_ic;
+ continue;
+ }
+ }
+ }
+ if(c==LABEL){
+ if(t>label) ierror(0);
+ forder(f);
+ emit(f,"%s%d:\n",labprefix,t);
+ continue;
+ }
+ if(c>=BEQ&&c<=BRA){
+ forder(f);
+ if(lastcomp&UNSIGNED) emit(f,"\tj%s\t%s%d\n",ccu[c-BEQ],labprefix,t);
+ else emit(f,"\tj%s\t%s%d\n",ccs[c-BEQ],labprefix,t);
+ continue;
+ }
+ if(c==MOVETOREG){
+ if(p->z.reg>8){
+ for(c=0;c<8;c++){
+ if(fst[c]==p->z.reg) fst[c]=0;
+ }
+ fload(f,&p->q1,DOUBLE);
+ fst[0]=p->z.reg;
+ continue;
+ }
+ move(f,&p->q1,0,0,p->z.reg,LONG);
+ continue;
+ }
+ if(c==MOVEFROMREG){
+ if(p->q1.reg>8){
+ if(fst[0]!=p->q1.reg){
+ for(c=0,reg=-1;c<8;c++){
+ if(fst[c]==p->q1.reg) reg=c;
+ }
+ if(reg<0) ierror(0);
+ fxch(f,reg);
+ }
+ emit(f,"\tfstpl\t");emit_obj(f,&p->z,DOUBLE);
+ emit(f,"\n");fpop();
+ continue;
+ }
+ move(f,0,p->q1.reg,&p->z,0,LONG);
+ continue;
+ }
+ if((p->q1.flags&(DREFOBJ|REG|KONST))==DREFOBJ||((p->q1.flags&DREFOBJ)&&ISBE(p->q1.dtyp))){
+ reg=get_reg(f,p,LONG);
+ move(f,&p->q1,0,0,reg,LONG);
+ p->q1.flags|=REG;p->q1.reg=reg;
+ p->q1.flags&=~KONST;
+ if(ISBE(p->q1.dtyp))
+ emit(f,"\tbswap\t%s\n",regnames[reg]);
+ }
+ if((p->q2.flags&(DREFOBJ|REG|KONST))==DREFOBJ||((p->q2.flags&DREFOBJ)&&ISBE(p->q2.dtyp))){
+ reg=get_reg(f,p,LONG);
+ move(f,&p->q2,0,0,reg,LONG);
+ p->q2.flags|=REG;p->q2.reg=reg;
+ p->q2.flags&=~KONST;
+ if(ISBE(p->q2.dtyp))
+ emit(f,"\tbswap\t%s\n",regnames[reg]);
+ }
+ if((p->z.flags&(DREFOBJ|REG|KONST))==DREFOBJ||((p->z.flags&DREFOBJ)&&ISBE(p->z.dtyp))){
+ reg=get_reg(f,p,LONG);
+ /* sehr unschoen */
+ if(c==GETRETURN&®==p->q1.reg) reg=get_reg(f,p,LONG);
+ move(f,&p->z,0,0,reg,LONG);
+ p->z.flags|=REG;p->z.reg=reg;
+ p->z.flags&=~KONST;
+ if(ISBE(p->z.dtyp))
+ emit(f,"\tbswap\t%s\n",regnames[reg]);
+ }
+ if((t&NQ)==LDOUBLE) p->typf=t=DOUBLE;
+ if(c==CONVERT&&(t&NQ)==LLONG&&(p->typf2&NQ)==LLONG) c=ASSIGN;
+ if(c==CONVERT){
+ int to=p->typf2&NU;
+ if(to==LDOUBLE) to=DOUBLE;
+ if((t&NU)==LONG) t=INT;
+ if((t&NU)==(UNSIGNED|LONG)||(t&NU)==POINTER) t=(UNSIGNED|INT);
+ if((to&NU)==LONG) to=INT;
+ if((to&NU)==(UNSIGNED|LONG)||(to&NU)==POINTER) to=(UNSIGNED|INT);
+ if((to&NQ)==LLONG){
+ int useqreg=0;
+ if(isreg(z))
+ reg=p->z.reg;
+ else if(isreg(q1)&®_pair(p->q1.reg,&rp)&®ok(rp.r1,t,0))
+ reg=useqreg=rp.r1;
+ else
+ reg=get_reg(f,p,INT);
+ if(!useqreg){
+ emit(f,"\tmovl\t");
+ if(isreg(q1)){
+ if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+ emit(f,"%s",regnames[rp.r1]);
+ }else{
+ emit_obj(f,&p->q1,INT);
+ }
+ emit(f,",%s\n",regnames[reg]);
+ }
+ if(!isreg(z)||p->z.reg!=reg)
+ move(f,0,reg,&p->z,0,t);
+ continue;
+ }
+ if((to&NQ)<=INT&&(t&NQ)<=LLONG){
+ if(isreg(z)){
+ reg=p->z.reg;
+ if(reg_pair(reg,&rp)) reg=rp.r1;
+ }else if(isreg(q1)&®ok(p->q1.reg,t,0))
+ reg=p->q1.reg;
+ else
+ reg=get_reg(f,p,((to&NQ)==CHAR||(t&NQ)==CHAR)?CHAR:LONG);
+ if((to&NQ)<=SHORT){
+ emit(f,"\tmov%c%cl\t",(to&UNSIGNED)?'z':'s',x_t[to&NQ]);
+ emit_obj(f,&p->q1,to);
+ emit(f,",%s\n",regnames[reg]);
+ }else{
+ move(f,&p->q1,0,0,reg,to);
+ }
+ if((t&NQ)==LLONG){
+ if(isreg(z)){
+ if(to&UNSIGNED)
+ emit(f,"\txorl\t%s,%s\n",regnames[rp.r2],regnames[rp.r2]);
+ else{
+ move(f,0,reg,0,rp.r2,INT);
+ emit(f,"\tsarl\t$31,%s\n",regnames[rp.r2]);
+ }
+ }else{
+ move(f,0,reg,&p->z,0,INT);
+ if(to&UNSIGNED){
+ emit(f,"\tmovl\t$0,");
+ emit_hword(f,&p->z);
+ emit(f,"\n");
+ }else{
+ emit(f,"\tsarl\t$31,%s\n",regnames[reg]);
+ emit(f,"\tmovl\t%s,",regnames[reg]);
+ emit_hword(f,&p->z);
+ emit(f,"\n");
+ }
+ }
+ }else
+ move(f,0,reg,&p->z,0,t);
+ continue;
+ }
+ if(ISFLOAT(t)){
+ if(ISFLOAT(to)){
+ if(isreg(q1)&&fst[0]==p->q1.reg){
+ if(isreg(z)){
+ if(p->z.reg==fst[0]) continue;
+ for(reg=0,c=7;c>=0;c--){
+ if(fst[c]==p->z.reg){reg=c;break;}
+ if(fst[c]<0) reg=c;
+ }
+ fst[reg]=p->z.reg;
+ }
+ emit(f,"\tfst%c\t",x_t[t&NQ]);
+ emit_obj(f,&p->z,t);emit(f,"\n");
+ continue;
+ }
+ fload(f,&p->q1,to);
+ fstore(f,&p->z,t);
+ continue;
+ }
+ if((to&NQ)<=SHORT){
+ if(isreg(q1)){
+ reg=p->q1.reg;
+ if(to&UNSIGNED){
+ emit(f,"\tandl\t$%ld,%s\n",(to&NQ)==CHAR?255L:65535L,regnames[reg]);
+ }else{
+/* emit(f,"\tc%ctl\t%s\n",x_t[to&NQ],regnames[reg]);*/
+ if((to&NQ)==SHORT){
+ emit(f,"\tmovswl\t%%%s,%s\n",regnames[reg]+2,regnames[reg]);
+ }else{
+ emit(f,"\tmovsbl\t%%%cl,%s\n",regnames[reg][2],regnames[reg]);
+ }
+ }
+ }else{
+ reg=get_reg(f,p,LONG);
+ if(to&UNSIGNED){
+ emit(f,"\tmovz%cl\t",x_t[to&NQ]);
+ }else{
+ emit(f,"\tmovs%cl\t",x_t[to&NQ]);
+ }
+ emit_obj(f,&p->q1,to);emit(f,",%s\n",regnames[reg]);
+ }
+ emit(f,"\tpushl\t%s\n",regnames[reg]);
+ emit(f,"\tfildl\t(%s)\n\taddl\t$4,%s\n",regnames[sp],regnames[sp]);
+ }else{
+ if(to&UNSIGNED){
+ emit(f,"\tpushl\t$0\n\tpushl\t");
+ push(4);
+ emit_obj(f,&p->q1,to);
+ emit(f,"\n\tfildq\t(%s)\n\taddl\t$8,%s\n",regnames[sp],regnames[sp]);
+ pop(4);
+ }else{
+ if(isreg(q1)){
+ emit(f,"\tpushl\t%s\n\tfildl\t(%s)\n\taddl\t$4,%s\n",regnames[p->q1.reg],regnames[sp],regnames[sp]);
+ }else{
+ emit(f,"\tfildl\t");emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ }
+ }
+ fpush(f);
+ fstore(f,&p->z,t);
+ continue;
+ }
+ if(ISFLOAT(to)){
+ int cwr;
+ if(isreg(z)&®ok(p->z.reg,CHAR,0))
+ cwr=p->z.reg;
+ else
+ cwr=get_reg(f,p,CHAR);
+ emit(f,"\tfnstcw\t%d(%s)\n",loff-4-stackoffset,regnames[sp]);
+ emit(f,"\tmovw\t%d(%s),%%%s\n",loff-4-stackoffset,regnames[sp],regnames[cwr]+2);
+ emit(f,"\tmovb\t$12,%%%ch\n",regnames[cwr][2]);
+ emit(f,"\tmovw\t%%%s,%d(%s)\n",regnames[cwr]+2,loff-2-stackoffset,regnames[sp]);
+ emit(f,"\tfldcw\t%d(%s)\n",loff-2-stackoffset,regnames[sp]);
+ if(isreg(q1)&&fst[0]==p->q1.reg){
+ if((t&NQ)==CHAR){
+ if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p,CHAR);
+ emit(f,"\tsubl\t$4,%s\n\tfistl\t(%s)\n\tmovsbl\t(%s),%s\n\taddl\t$4,%s\n",regnames[sp],regnames[sp],regnames[sp],regnames[reg],regnames[sp]);
+ move(f,0,reg,&p->z,0,t);
+ }else{
+ if(isreg(z)){
+ emit(f,"\tsubl\t$4,%s\n\tfistl\t(%s)\n\tmov%c\t(%s),",regnames[sp],regnames[sp],x_t[t&NQ],regnames[sp]);
+ push(4);
+ emit_obj(f,&p->z,t);emit(f,"\n\taddl\t$4,%s\n",regnames[sp]);
+ pop(4);
+ }else{
+ emit(f,"\tfist%c\t",x_t[t&NQ]);
+ emit_obj(f,&p->z,t);emit(f,"\n");
+ }
+ }
+ }else{
+ fload(f,&p->q1,to);
+ if((t&NQ)==CHAR){
+ if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p,CHAR);
+ emit(f,"\tsubl\t$4,%s\n\tfistpl\t(%s)\n\tmovsbl\t(%s),%s\n\taddl\t$4,%s\n",regnames[sp],regnames[sp],regnames[sp],regnames[reg],regnames[sp]);
+ fpop(); move(f,0,reg,&p->z,0,t);
+ }else{
+ if(isreg(z)){
+ emit(f,"\tsubl\t$4,%s\n\tfistpl\t(%s)\n\tmov%c\t(%s),",regnames[sp],regnames[sp],x_t[t&NQ],regnames[sp]);
+ push(4);
+ emit_obj(f,&p->z,t);
+ emit(f,"\n\taddl\t$4,%s\n",regnames[sp]);
+ pop(4);
+ fpop();
+ }else{
+ emit(f,"\tfistp%s\t",(t&NQ)==SHORT?"":"l");
+ emit_obj(f,&p->z,t);emit(f,"\n");fpop();
+ }
+ }
+ }
+ emit(f,"\tfldcw\t%d(%s)\n",loff-4-stackoffset,regnames[sp]);
+ continue;
+ }
+pric2(stdout,p);
+ ierror(0);
+ }
+ if(c==MINUS||c==KOMPLEMENT){
+ char *s;
+ if(ISFLOAT(t)){
+ if(isreg(z)&&p->z.reg==9&&isreg(q1)&&p->q1.reg==9){
+ emit(f,"\tfchs\n");
+ continue;
+ }
+ fload(f,&p->q1,t);
+ emit(f,"\tfchs\n");
+ emit(f,"\tfstp%c\t",x_t[t&NQ]);
+ emit_obj(f,&p->z,t);emit(f,"\n");
+ fpop();
+ continue;
+ }
+ if(c==MINUS) s="neg"; else s="not";
+ if(compare_objects(&p->q1,&p->q2)){
+ emit(f,"\t%s%c\t",s,x_t[t&NQ]);
+ emit_obj(f,&p->z,t);emit(f,"\n");
+ continue;
+ }
+ if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p,t);
+ move(f,&p->q1,0,0,reg,t);
+ emit(f,"\t%s%c\t%s\n",s,x_t[t&NQ],regnames[reg]);
+ move(f,0,reg,&p->z,0,t);
+ continue;
+ }
+ if(c==SETRETURN){
+ if(p->z.reg){
+ if(p->z.reg==9){
+ if(!isreg(q1)||fst[0]!=p->q1.reg)
+ fload(f,&p->q1,t);
+ }else{
+ move(f,&p->q1,0,0,p->z.reg,t);
+ }
+ BSET(regs_modified,p->z.reg);
+ }
+ continue;
+ }
+ if(c==GETRETURN){
+ if(p->q1.reg){
+ if(p->q1.reg==9){
+ if(!isreg(z)||fst[0]!=p->z.reg)
+ fstore(f,&p->z,t);
+ }else{
+ move(f,0,p->q1.reg,&p->z,0,t);
+ }
+ }
+ continue;
+ }
+ if(c==CALL){
+ int reg;
+ if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ }else{
+ if(p->q1.flags&DREFOBJ){
+ if(!(p->q1.flags®)) ierror(0);
+ emit(f,"\tcall\t*%s\n",regnames[p->q1.reg]);
+ }else{
+ emit(f,"\tcall\t");emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ }
+ if(!zmeqto(l2zm(0L),p->q2.val.vmax)){
+ notpopped+=zm2l(p->q2.val.vmax);
+ dontpop-=zm2l(p->q2.val.vmax);
+ if(!(g_flags[2]&USEDFLAG)&&!vlas&&stackoffset==-notpopped){
+ /* Entfernen der Parameter verzoegern */
+ }else{
+ emit(f,"\taddl\t$%ld,%%esp\n",zm2l(p->q2.val.vmax));
+ pop(zm2l(p->q2.val.vmax));
+ notpopped-=zm2l(p->q2.val.vmax);
+ }
+ }
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+ bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+ }else{
+ int i;
+ for(i=1;i<=MAXR;i++){
+ if(regscratch[i]) BSET(regs_modified,i);
+ }
+ }
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax);
+ if(ISFLOAT(t)){
+ if(c==ASSIGN){
+ prfst(f,"fassign");
+ fload(f,&p->q1,t);
+ fstore(f,&p->z,t);
+ continue;
+ }else if(isreg(q1)){
+ prfst(f,"fpush");
+ emit(f,"\tsubl\t$%ld,%s\n",zm2l(sizetab[t&NQ]),regnames[sp]);
+ push(zm2l(sizetab[t&NQ]));
+ if(fst[0]==p->q1.reg){
+ emit(f,"\tfst%c\t(%s)\n",x_t[t&NQ],regnames[sp]);
+ }else{
+ fload(f,&p->q1,t);
+ emit(f,"\tfstp%c\t(%s)\n",x_t[t&NQ],regnames[sp]);
+ fpop();
+ }
+ continue;
+ }
+ }
+ if((t&NQ)==LLONG){
+ if(c==ASSIGN){
+ if(isconst(q1)||isreg(q1)||isreg(z)){
+ move(f,&p->q1,0,&p->z,0,t);
+ }else{
+ int r=get_reg(f,p,INT);
+ emit(f,"\tmovl\t");
+ emit_lword(f,&p->q1);
+ emit(f,",%s\n",regnames[r]);
+ emit(f,"\tmovl\t%s,",regnames[r]);
+ emit_lword(f,&p->z);
+ emit(f,"\n");
+ emit(f,"\tmovl\t");
+ emit_hword(f,&p->q1);
+ emit(f,",%s\n",regnames[r]);
+ emit(f,"\tmovl\t%s,",regnames[r]);
+ emit_hword(f,&p->z);
+ emit(f,"\n");
+ }
+ }else{
+ emit(f,"\tpushl\t");
+ emit_hword(f,&p->q1);
+ emit(f,"\n");
+ push(4);
+ emit(f,"\tpushl\t");
+ emit_lword(f,&p->q1);
+ emit(f,"\n");
+ push(4);
+ }
+ continue;
+ }
+ if(!ISSCALAR(t)||!zmeqto(p->q2.val.vmax,sizetab[t&NQ])||!zmleq(p->q2.val.vmax,l2zm(4L))){
+ int mdi=di,msi=si,m=0;long l;
+ l=zm2l(p->q2.val.vmax);
+ if(regs[cx]){m|=1;if(!cxl)cxl=++label;emit(f,"\tmovl\t%s,%s%d\n",regnames[cx],labprefix,cxl);}
+ if(regs[msi]||!regused[msi]){m|=2;if(!sil)sil=++label;emit(f,"\tmovl\t%s,%s%d\n",regnames[msi],labprefix,sil);}
+ if(regs[mdi]||!regused[mdi]){m|=4;if(!dil)dil=++label;emit(f,"\tmovl\t%s,%s%d\n",regnames[mdi],labprefix,dil);}
+ if((p->z.flags®)&&p->z.reg==msi&&(p->q1.flags®)&&p->q1.reg==mdi){
+ msi=di;mdi=si;
+ m|=8;
+ }
+ if(!(p->z.flags®)||p->z.reg!=msi){
+ emit(f,"\tleal\t");emit_obj(f,&p->q1,t);
+ emit(f,",%s\n",regnames[msi]);
+ }
+ if(c==PUSH){
+ emit(f,"\tsubl\t$%ld,%s\n\tmovl\t%s,%s\n",l,regnames[sp],regnames[sp],regnames[mdi]);
+ push(l);
+ l=zm2l(p->z.val.vmax);
+ }else{
+ emit(f,"\tleal\t");emit_obj(f,&p->z,t);
+ emit(f,",%s\n",regnames[mdi]);
+ }
+ if((p->z.flags®)&&p->z.reg==msi){
+ emit(f,"\tleal\t");emit_obj(f,&p->q1,t);
+ emit(f,",%s\n",regnames[msi]);
+ }
+ if(m&8){
+ msi=si;mdi=di;
+ emit(f,"\txchg\t%s,%s\n",regnames[msi],regnames[mdi]);
+ }
+ if((t&NQ)==ARRAY||(t&NQ)==CHAR||l<4){
+ emit(f,"\tmovl\t$%ld,%s\n\trep\n\tmovsb\n",l,regnames[cx]);
+ }else{
+ if(l>=8)
+ emit(f,"\tmovl\t$%ld,%s\n\trep\n",l/4,regnames[cx]);
+ emit(f,"\tmovsl\n");
+ if(l&2) emit(f,"\tmovsw\n");
+ if(l&1) emit(f,"\tmovsb\n");
+ }
+ if(m&4) emit(f,"\tmovl\t%s%d,%s\n",labprefix,dil,regnames[mdi]);
+ if(m&2) emit(f,"\tmovl\t%s%d,%s\n",labprefix,sil,regnames[msi]);
+ if(m&1) emit(f,"\tmovl\t%s%d,%s\n",labprefix,cxl,regnames[cx]);
+ continue;
+ }
+ if(c==PUSH){
+ emit(f,"\tpush%c\t",(t&NQ)==FLOAT?x_t[LONG]:x_t[t&NQ]);
+ emit_obj(f,&p->q1,t);emit(f,"\n");
+ push(zm2l(p->q2.val.vmax));
+ continue;
+ }
+ if(c==ASSIGN){
+ if(isconst(q1)){
+ move(f,&p->q1,0,&p->z,0,t);
+ continue;
+ }
+ if(isreg(z)) reg=p->z.reg;
+ else if(isreg(q1)) reg=p->q1.reg;
+ else reg=get_reg(f,p,t);
+ move(f,&p->q1,0,0,reg,t);
+ move(f,0,reg,&p->z,0,t);
+ continue;
+ }
+ ierror(0);
+ }
+ if(c==ADDRESS){
+ if(isreg(z)) reg=p->z.reg; else reg=get_reg(f,p,LONG);
+ emit(f,"\tleal\t");emit_obj(f,&p->q1,t);
+ emit(f,",%s\n",regnames[reg]);
+ move(f,0,reg,&p->z,0,POINTER);
+ continue;
+ }
+ if(c==TEST){
+ lastcomp=t;
+ if(ISFLOAT(t)){
+ if(isreg(q1)&&fst[0]==p->q1.reg){
+ emit(f,"\tftst\n");lastcomp|=UNSIGNED;
+ continue;
+ }else{
+ p->code=c=COMPARE;
+ p->q2.flags=KONST;
+ p->q2.val.vldouble=d2zld(0.0);
+ if((t&NQ)==FLOAT) p->q2.val.vfloat=zld2zf(p->q2.val.vldouble);
+ if((t&NQ)==DOUBLE) p->q2.val.vdouble=zld2zd(p->q2.val.vldouble);
+
+ /* fall through to COMPARE */
+ }
+ }else{
+ if(isvconst(q1)){
+ reg=get_reg(f,p,t);
+ move(f,&p->q1,0,0,reg,t);
+ p->q1.flags=REG;
+ p->q1.reg=reg;
+ }
+ if((t&NQ)==LLONG){
+ reg=get_reg(f,p,INT);
+ if(isreg(q1)){
+ if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+ move(f,0,rp.r1,0,reg,INT);
+ emit(f,"\torl\t%s,%s\n",regnames[rp.r2],regnames[reg]);
+ }else{
+ move(f,&p->q1,0,0,reg,INT);
+ emit(f,"\torl\t");
+ emit_hword(f,&p->q1);
+ emit(f,",%s\n",regnames[reg]);
+ }
+ continue;
+ }
+ if(isreg(q1)){
+ emit(f,"\ttest%c\t",x_t[t&NQ]);
+ emit_obj(f,&p->q1,t);emit(f,",");
+ emit_obj(f,&p->q1,t);emit(f,"\n");
+ }else{
+ emit(f,"\tcmp%c\t$0,",x_t[t&NQ]);
+ emit_obj(f,&p->q1,t);emit(f,"\n");
+ }
+ continue;
+ }
+ }
+ if(c==COMPARE){
+ lastcomp=t;
+ if(isreg(q2)||isvconst(q1)){
+ struct IC *b=p->next;
+ struct obj o;
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ while(b&&b->code==FREEREG) b=b->next;
+ if(!b) ierror(0);
+ if(b->code==BLT) b->code=BGT;
+ else if(b->code==BLE) b->code=BGE;
+ else if(b->code==BGT) b->code=BLT;
+ else if(b->code==BGE) b->code=BLE;
+ }
+ if(ISFLOAT(t)){
+ prfst(f,"fcomp");
+ if(isreg(q1)&&p->q1.reg==fst[0]){
+ emit(f,"\tfcom%c\t",x_t[t&NQ]);
+ emit_obj(f,&p->q2,t);emit(f,"\n");
+ }else{
+ fload(f,&p->q1,t);
+ emit(f,"\tfcomp%c\t",x_t[t&NQ]);
+ emit_obj(f,&p->q2,t);emit(f,"\n");
+ fpop();
+ }
+ if(regs[ax]) emit(f,"\tpushl\t%s\n",regnames[ax]);
+ emit(f,"\tfstsw\n\tsahf\n");
+ if(regs[ax]) emit(f,"\tpopl\t%s\n",regnames[ax]);
+ lastcomp|=UNSIGNED;
+ continue;
+ }
+ if(!isreg(q1)){
+ if(!isreg(q2)&&(!isvconst(q2)||isvconst(q1))){
+ reg=get_reg(f,p,t);
+ move(f,&p->q1,0,0,reg,t);
+ p->q1.flags=REG;
+ p->q1.reg=reg;
+ }
+ }
+ if(isreg(q1)&&isconst(q2)){
+ eval_const(&p->q2.val,t);
+ if(zmeqto(vmax,l2zm(0L))){
+ emit(f,"\ttest%c\t",x_t[t&NQ]);
+ emit_obj(f,&p->q1,t);emit(f,",");
+ emit_obj(f,&p->q1,t);emit(f,"\n");
+ continue;
+ }
+ }
+ if(isreg(q2)&&isconst(q1)){
+ eval_const(&p->q1.val,t);
+ if(zmeqto(vmax,l2zm(0L))){
+ emit(f,"\ttest%c\t",x_t[t&NQ]);
+ emit_obj(f,&p->q2,t);emit(f,",");
+ emit_obj(f,&p->q2,t);emit(f,"\n");
+ continue;
+ }
+ }
+ emit(f,"\tcmp%c\t",x_t[t&NQ]);
+ emit_obj(f,&p->q2,t);emit(f,",");
+ emit_obj(f,&p->q1,t);emit(f,"\n");
+ continue;
+ }
+ if(ISFLOAT(t)){
+ char s[2];
+ prfst(f,"fmath");
+ if(isreg(q2)) s[0]=0; else {s[0]=x_t[t&NQ];s[1]=0;}
+ if(isreg(z)&&isreg(q1)&&p->q1.reg==fst[0]&&p->z.reg==fst[0]){
+ emit(f,"\t%s%s\t",farithmetics[c-LSHIFT],s);
+ emit_obj(f,&p->q2,t); emit(f,"\n");continue;
+ }
+ fload(f,&p->q1,t);
+ emit(f,"\t%s%s\t",farithmetics[c-LSHIFT],s);
+ emit_obj(f,&p->q2,t); emit(f,"\n");
+ fstore(f,&p->z,t); continue;
+ }
+ if((c==MULT||((c==DIV||c==MOD)&&(p->typf&UNSIGNED)))&&isconst(q2)){
+ long ln;
+ eval_const(&p->q2.val,t);
+ if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+ if(ln=pof2(vumax)){
+ if(c==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ p->code=AND;
+ }else{
+ vmax=l2zm(ln-1);
+ if(c==DIV) p->code=RSHIFT; else p->code=LSHIFT;
+ }
+ c=p->code;
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ if(c==AND){
+ insert_const(&p->q2.val,t);
+ }else{
+ insert_const(&p->q2.val,INT);
+ p->typf2=INT;
+ }
+ }
+ }
+ }
+ if(c==MOD||c==DIV){
+ int m=0;
+ BSET(regs_modified,dx);
+ BSET(regs_modified,ax);
+ if(regs[ax]&&(!isreg(z)||p->z.reg!=ax)){
+ emit(f,"\tpushl\t%s\n",regnames[ax]);
+ push(4);
+ m|=1;
+ }
+ if(isreg(q2)&&p->q2.reg==ax){
+ emit(f,"\tpushl\t%s\n",regnames[ax]);
+ push(4);
+ m|=16;
+ }
+ if(regs[dx]&&(!isreg(z)||p->z.reg!=dx)){
+ emit(f,"\tpushl\t%s\n",regnames[dx]);
+ push(4);
+ m|=2;
+ }
+ if((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&(p->q2.reg==ax||p->q2.reg==dx)){
+ move(f,&p->q2,0,0,dx,t);
+ emit(f,"\tpushl\t%s\n",regnames[dx]);
+ push(4);
+ m|=8;
+ }
+ if(isreg(q1)&&p->q1.reg==dx&&(m&10)==10)
+ emit(f,"\tmovl\t4(%s),%s\n",regnames[sp],regnames[ax]);
+ else
+ move(f,&p->q1,0,0,ax,t);
+ if(isconst(q2)){
+ emit(f,"\tpush%c\t",x_t[t&NQ]);emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ push(4);
+ m|=4;
+ }
+ if(isreg(q2)&&p->q2.reg==dx){
+ emit(f,"\tpushl\t%s\n",regnames[dx]);
+ push(4);
+ m|=4;
+ }
+ if(t&UNSIGNED) emit(f,"\txorl\t%s,%s\n\tdivl\t",regnames[dx],regnames[dx]);
+ else emit(f,"\tcltd\n\tidivl\t");
+ if((m&12)||(isreg(q2)&&p->q2.reg==dx)){
+ emit(f,"(%s)",regnames[sp]);
+ }else if(isreg(q2)&&p->q2.reg==ax){
+ emit(f,"%s(%s)",(m&10)?"4":"",regnames[sp]);
+ }else{
+ emit_obj(f,&p->q2,t);
+ }
+ emit(f,"\n");
+ if(c==DIV) move(f,0,ax,&p->z,0,t);
+ else move(f,0,dx,&p->z,0,t);
+ if(m&4){ emit(f,"\taddl\t$%ld,%s\n",zm2l(sizetab[t&NQ]),regnames[sp]);pop(4);}
+ if(m&8){ emit(f,"\tpopl\t%s\n",regnames[dx]);pop(4);}
+ if(m&2){ emit(f,"\tpopl\t%s\n",regnames[dx]);pop(4);}
+ if(m&1){ emit(f,"\tpopl\t%s\n",regnames[ax]);pop(4);}
+ if(m&16){ emit(f,"\taddl\t$%ld,%s\n",zm2l(sizetab[t&NQ]),regnames[sp]);pop(4);}
+ continue;
+ }
+ if(!isconst(q2)&&(c==LSHIFT||c==RSHIFT)){
+ char *s=arithmetics[c-LSHIFT];
+ int fl=0;
+ if(c==RSHIFT&&(t&UNSIGNED)) s="shr";
+ if(((p->q1.flags®)&&p->q1.reg==cx)||((p->z.flags®)&&p->z.reg==cx)
+ ||(!compare_objects(&p->q1,&p->z)&&!isreg(q1))){
+ fl=regs[cx];regs[cx]=2; /* don't want cx */
+ reg=get_reg(f,p,t);
+ regs[cx]=fl;
+ if(isreg(z)&&p->z.reg==cx) fl=0;
+ if(fl){emit(f,"\tpushl\t%s\n",regnames[cx]);push(4);}
+ move(f,&p->q1,0,0,reg,t);
+ move(f,&p->q2,0,0,cx,t);
+ emit(f,"\t%s%c\t%%cl,%s\n",s,x_t[t&NQ],mregname(reg,t));
+ move(f,0,reg,&p->z,0,t);
+ if(fl){emit(f,"\tpopl\t%s\n",regnames[cx]);pop(4);}
+ continue;
+ }else{
+ if(!isreg(q2)||p->q2.reg!=cx){
+ if(regs[cx]){emit(f,"\tpushl\t%s\n",regnames[cx]);push(4);fl=1;}
+ move(f,&p->q2,0,0,cx,t);
+ }
+ if(compare_objects(&p->q1,&p->z)){
+ emit(f,"\t%s%c\t%%cl,",s,x_t[t&NQ]);
+ emit_obj(f,&p->z,t);emit(f,"\n");
+ }else{
+ move(f,0,p->q1.reg,&p->z,0,t);
+ emit(f,"\t%s%c\t%%cl,",s,x_t[t&NQ]);
+ emit_obj(f,&p->z,t);emit(f,"\n");
+ }
+ if(fl) {emit(f,"\tpopl\t%s\n",regnames[cx]);pop(4);}
+ continue;
+ }
+ }
+ if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)){
+ char *s;
+ if(c>=OR&&c<=AND) s=logicals[c-OR];
+ else s=arithmetics[c-LSHIFT];
+ if(c==RSHIFT&&(t&UNSIGNED)) s="shr";
+ if(c!=MULT&&compare_objects(&p->q1,&p->z)){
+ if(isreg(z)||isreg(q1)||isconst(q2)){
+ if(isconst(q2)&&(c==ADD||c==SUB)){
+ eval_const(&p->q2.val,t);
+ if(zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL))&&zldeqto(vldouble,d2zld(1.0))){
+ if(c==ADD) s="inc"; else s="dec";
+ emit(f,"\t%s%c\t",s,x_t[t&NQ]);
+ emit_obj(f,&p->z,t);emit(f,"\n");
+ continue;
+ }
+ }
+ emit(f,"\t%s%c\t",s,x_t[t&NQ]);
+ emit_obj(f,&p->q2,t);emit(f,",");
+ emit_obj(f,&p->z,t);emit(f,"\n");
+ continue;
+ }else{
+ if(isreg(q2)) reg=p->q2.reg; else reg=get_reg(f,p,t);
+ move(f,&p->q2,0,0,reg,t);
+ emit(f,"\t%s%c\t%s",s,x_t[t&NQ],mregname(reg,t));
+ emit(f,","); emit_obj(f,&p->z,t);emit(f,"\n");
+ continue;
+ }
+ }
+ if(c==AND&&isreg(z)){
+ /* can we use test instruction? */
+ struct IC *p2=p->next;
+ while(p2->code==ALLOCREG||p2->code==FREEREG)
+ p2=p2->next;
+ if(p2->code==TEST&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg){
+ struct IC *p3=p2->next;
+ while(p3->code==ALLOCREG||p3->code==FREEREG){
+ if(p3->code==FREEREG&&p3->q1.reg==p->z.reg)
+ break;
+ p3=p3->next;
+ }
+ if(p3->code==FREEREG&&p3->q1.reg==p->z.reg){
+ /* we can use test */
+ p2->code=NOP;
+ if(notpopped&&!dontpop){
+ emit(f,"\taddl\t$%ld,%%esp\n",notpopped);
+ pop(notpopped);
+ notpopped=0;
+ }
+ if(isconst(q1)){
+ struct obj tmp=p->q1;
+ p->q1=p->q2;
+ p->q2=tmp;
+ }
+ if(!isreg(q1)&&!isreg(q2)&&!isconst(q2)){
+ int r=get_reg(f,p,t);
+ move(f,&p->q1,0,0,r,t);
+ p->q1.flags=REG;
+ p->q1.reg=r;
+ }
+ emit(f,"\ttest%c\t",x_t[t&NQ]);
+ emit_obj(f,&p->q2,t);
+ emit(f,",");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ continue;
+ }
+ }
+ }
+
+ if(isreg(z)&&(p->q2.flags®)&&p->q2.reg==p->z.reg){
+ if(c==ADD||c==AND||c==OR||c==XOR){
+ struct obj tmp;
+ tmp=p->q1;
+ p->q1=p->q2;
+ p->q2=tmp;
+ }
+ }
+ if(isreg(z)&&(!(p->q2.flags®)||p->q2.reg!=p->z.reg)) reg=p->z.reg; else reg=get_reg(f,p,t);
+ move(f,&p->q1,0,0,reg,t);
+ if(isconst(q2)&&(c==ADD||c==SUB)){
+ eval_const(&p->q2.val,t);
+ if(zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL))&&zldeqto(vldouble,d2zld(1.0))){
+ if(c==ADD) s="inc"; else s="dec";
+ emit(f,"\t%s%c\t%s\n",s,x_t[t&NQ],mregname(reg,t));
+ }else{
+ emit(f,"\t%s%c\t",s,x_t[t&NQ]);
+ emit_obj(f,&p->q2,t);emit(f,",%s\n",mregname(reg,t));
+ }
+ }else{
+ emit(f,"\t%s%c\t",s,x_t[t&NQ]);
+ emit_obj(f,&p->q2,t);emit(f,",%s\n",mregname(reg,t));
+ }
+ move(f,0,reg,&p->z,0,t);
+ continue;
+ }
+ ierror(0);
+ }
+ if(notpopped){
+ emit(f,"\taddl\t$%ld,%%esp\n",notpopped);
+ pop(notpopped);notpopped=0;
+ }
+ function_bottom(f,v,loff);
+ if(debug_info){
+ emit(f,"%s%d:\n",labprefix,++label);
+ dwarf2_function(f,v,label);
+ if(f) section=-1;
+ }
+}
+
+int shortcut(int code,int typ)
+{
+ return(0);
+}
+
+void cleanup_cg(FILE *f)
+{
+ struct fpconstlist *p;
+ unsigned char *ip;
+
+ title(f);
+ while(p=firstfpc){
+ if(f){
+ if(section!=CODE){emit(f,codename);if(f) section=CODE;}
+ emit(f,"\t.align\t4\n");
+ emit(f,"%s%d:\n\t.long\t",labprefix,p->label);
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+ if((p->typ&NQ)==DOUBLE||(p->typ&NQ)==LDOUBLE){
+ emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+ }
+ emit(f,"\n");
+ }
+ firstfpc=p->next;
+ free(p);
+ }
+ if(f){
+ if(section!=BSS){emit(f,bssname);if(f) section=BSS;}
+ if(cxl) emit(f,"\t.lcomm\t%s%d,4\n",labprefix,cxl);
+ if(sil) emit(f,"\t.lcomm\t%s%d,4\n",labprefix,sil);
+ if(dil) emit(f,"\t.lcomm\t%s%d,4\n",labprefix,dil);
+ }
+}
+void init_db(FILE *f)
+{
+ dwarf2_setup(sizetab[POINTER],".byte",".2byte",".4byte",".4byte",labprefix,idprefix,".section");
+ dwarf2_print_comp_unit_header(f);
+}
+void cleanup_db(FILE *f)
+{
+ dwarf2_cleanup(f);
+ if(f) section=-1;
+}
+
+
+void insert_const(union atyps *p,int t)
+/* Traegt Konstante in entprechendes Feld ein. */
+{
+ if(!p) ierror(0);
+ t&=NU;
+ if(ISBE(t))
+ t=LETYPE(t);
+ if(t==CHAR) {p->vchar=vchar;return;}
+ if(t==SHORT) {p->vshort=vshort;return;}
+ if(t==INT) {p->vint=vint;return;}
+ if(t==LONG) {p->vlong=vlong;return;}
+ if(t==LLONG) {p->vllong=vllong;return;}
+ if(t==MAXINT) {p->vmax=vmax;return;}
+ if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+ if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+ if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+ if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+ if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+ if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+ if(t==FLOAT) {p->vfloat=vfloat;return;}
+ if(t==DOUBLE) {p->vdouble=vdouble;return;}
+ if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+ if(t==POINTER) {p->vulong=vulong;return;}
+}
+
+void eval_const(union atyps *p,int t)
+/* Weist bestimmten globalen Variablen Wert einer CEXPR zu. */
+{
+ int f=t&NQ;
+ if(ISBE(f))
+ f=LETYPE(f);
+ if(!p) ierror(0);
+ if(f==MAXINT||(f>=CHAR&&f<=LLONG)){
+ if(!(t&UNSIGNED)){
+ if(f==CHAR) vmax=zc2zm(p->vchar);
+ else if(f==SHORT)vmax=zs2zm(p->vshort);
+ else if(f==INT) vmax=zi2zm(p->vint);
+ else if(f==LONG) vmax=zl2zm(p->vlong);
+ else if(f==LLONG) vmax=zll2zm(p->vllong);
+ else if(f==MAXINT) vmax=p->vmax;
+ else ierror(0);
+ vumax=zm2zum(vmax);
+ vldouble=zm2zld(vmax);
+ }else{
+ if(f==CHAR) vumax=zuc2zum(p->vuchar);
+ else if(f==SHORT)vumax=zus2zum(p->vushort);
+ else if(f==INT) vumax=zui2zum(p->vuint);
+ else if(f==LONG) vumax=zul2zum(p->vulong);
+ else if(f==LLONG) vumax=zull2zum(p->vullong);
+ else if(f==MAXINT) vumax=p->vumax;
+ else ierror(0);
+ vmax=zum2zm(vumax);
+ vldouble=zum2zld(vumax);
+ }
+ }else{
+ if(ISPOINTER(f)){
+ vumax=zul2zum(p->vulong);
+ vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+ }else{
+ if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+ else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+ else vldouble=p->vldouble;
+ vmax=zld2zm(vldouble);
+ vumax=zld2zum(vldouble);
+ }
+ }
+ vfloat=zld2zf(vldouble);
+ vdouble=zld2zd(vldouble);
+ vuchar=zum2zuc(vumax);
+ vushort=zum2zus(vumax);
+ vuint=zum2zui(vumax);
+ vulong=zum2zul(vumax);
+ vullong=zum2zull(vumax);
+ vchar=zm2zc(vmax);
+ vshort=zm2zs(vmax);
+ vint=zm2zi(vmax);
+ vlong=zm2zl(vmax);
+ vllong=zm2zll(vmax);
+}
+void printval(FILE *f,union atyps *p,int t)
+/* Gibt atyps aus. */
+{
+ t&=NU;
+ if(ISBE(t)){
+ fprintf(f,"B");
+ t=LETYPE(t);
+ }
+ if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+ if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+ if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+ if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+ if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+ if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+ if(t==(UNSIGNED|INT)){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+ if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+ if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+ if(t==MAXINT){fprintf(f,"M");printzm(f,p->vmax);}
+ if(t==(UNSIGNED|MAXINT)){fprintf(f,"UM");printzum(f,p->vumax);}
+ /*FIXME*/
+ if(t==POINTER){fprintf(f,"P");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+}
+void emitval(FILE *f,union atyps *p,int t)
+/* Gibt atyps aus. */
+{
+ t&=NU;
+ /*FIXME?*/
+ if(ISBE(t))
+ t=LETYPE(t);
+ if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+ if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+ if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+ if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+ if(t==LDOUBLE){emitzld(f,p->vldouble);}
+ if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+ if(t==(UNSIGNED|INT)){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+ if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+ if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+ if(t==MAXINT){emitzm(f,p->vmax);}
+ if(t==(UNSIGNED|MAXINT)){emitzum(f,p->vumax);}
+ /*FIXME*/
+ if(t==POINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+}
+
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+ char *attr;
+ while(p){
+ if(ISSCALAR(p->flags)&&(p->flags&NQ)!=CHAR&&(attr=p->attr)&&strstr(attr,"bigendian")){
+ if(!ISBE(p->flags))
+ p->flags++;
+ }
+ if(ISSCALAR(p->flags)&&(p->flags&NQ)!=CHAR&&(attr=p->attr)&&strstr(attr,"littleendian")){
+ if(ISBE(p->flags))
+ p->flags--;
+ }
+ p=p->next;
+ }
+}
diff --git a/machines/i386/machine.dt b/machines/i386/machine.dt
new file mode 100755
index 0000000..47b1bfa
--- /dev/null
+++ b/machines/i386/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S32BULE S32BUBE
+
+
diff --git a/machines/i386/machine.h b/machines/i386/machine.h
new file mode 100755
index 0000000..6c1aed5
--- /dev/null
+++ b/machines/i386/machine.h
@@ -0,0 +1,176 @@
+/* Example of a code-generator for an Intel 386 or higher. */
+
+#include "dt.h"
+
+/* We have extended types! What we have to do to support them: */
+/* - #define HAVE_EXT_TYPES
+ - #undef all standard types
+ - #define all standard types plus new types
+ - write eval_const and insert_const
+ - write typedefs for zmax and zumax
+ - write typname[]
+ - write conv_typ()
+ - optionally #define ISPOINTER, ISARITH, ISINT etc.
+ - optionally #define HAVE_TGT_PRINTVAL and write printval
+ - optionally #define POINTER_TYPE
+ - optionally #define HAVE_TGT_FALIGN and write falign
+ - optionally #define HAVE_TGT_SZOF and write szof
+ - optionally add functions for attribute-handling
+*/
+#define HAVE_EXT_TYPES 1
+
+#define HAVE_TGT_PRINTVAL
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef MAXINT
+#undef MAX_TYPE
+
+#define CHAR 1
+#define SHORT 2
+#define BSHORT 3
+#define INT 4
+#define BINT 5
+#define LONG 6
+#define BLONG 7
+#define LLONG 8
+#define BLLONG 9
+#define FLOAT 10
+#define BFLOAT 11
+#define DOUBLE 12
+#define BDOUBLE 13
+#define LDOUBLE 14
+#define BLDOUBLE 15
+#define VOID 16
+#define POINTER 17
+#define BPOINTER 18
+#define ARRAY 19
+#define STRUCT 20
+#define UNION 21
+#define ENUM 22
+#define FUNKT 23
+
+#define MAXINT 24 /* should not be accesible to application */
+
+#define MAX_TYPE MAXINT
+
+#define ISPOINTER(x) ((x&NQ)==POINTER||(x&NQ)==BPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=CHAR&&(x&NQ)<=BPOINTER)
+#define ISINT(x) ((x&NQ)>=CHAR&&(x&NQ)<=BLLONG)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+ zchar vchar;
+ zuchar vuchar;
+ zshort vshort;
+ zushort vushort;
+ zint vint;
+ zuint vuint;
+ zlong vlong;
+ zulong vulong;
+ zllong vllong;
+ zullong vullong;
+ zmax vmax;
+ zumax vumax;
+ zfloat vfloat;
+ zdouble vdouble;
+ zldouble vldouble;
+};
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Not used in this code-generrator. */
+struct AddressingMode{
+ int mode;
+ int base;
+ int idx;
+ int scal;
+ zmax offset;
+ struct Var *v;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR 18
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 10
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P INT
+#define MAXADDI2P LONG
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 0
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 1
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/* We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+#define JUMP_TABLE_DENSITY 0.8
+#define JUMP_TABLE_LENGTH 4
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+/* support for variable-length arrays */
+#define ALLOCVLA_REG 1
+#define ALLOCVLA_INLINEASM "\tsubl\t%eax,%esp\n\tandl\t$-5,%esp\n\tmovl\t%esp,%eax"
+/* TODO: find a better solution some time */
+#define FREEVLA_REG 0
+#define FREEVLA_INLINEASM "\tmovl\t(%esp),%esp\n\tsubl\t$4,%esp"
+#define OLDSPVLA_INLINEASM "\tmovl\t%esp,%eax"
+#define FPVLA_REG 7
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 1
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 1
+
diff --git a/machines/m65/compress.c b/machines/m65/compress.c
new file mode 100644
index 0000000..19f033d
--- /dev/null
+++ b/machines/m65/compress.c
@@ -0,0 +1,123 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "vcpr.h"
+
+
+const char tg_copyright[]="6502 code compressor V0.1 (c) 2020 by Volker Barthelmann";
+
+char *inst[]={
+ "lda","ldx","sta","stx","ldy","sty",
+ "adc","sbc","and","ora","eor",
+ "bne","beq","bcc","bcs","bvs","bvc","bpl","bmi",
+ "clc","sec",
+ /*"pla","pha",*/
+ "txa","tax","tya","tay",
+ "inc","dec","dex","inx","iny","dey",
+ /*"rts","rti",*/"jsr","jmp",
+ "cmp","cpx","cpy",
+ "asl","lsr","ror","rol"
+};
+
+int minsave=5;
+
+void parse_line(char *s,line *p)
+{
+ int l,i;
+ static int secok=0;
+ char buf[16],buf2[16],*e;
+
+ if(sscanf(s," %8s %8s",buf,buf2)==2&&!strcmp(buf,"section")){
+ if(!strcmp(buf2,"text"))
+ secok=1;
+ else
+ secok=0;
+ p->flags=BARRIER;
+ return;
+ }
+
+ if(sscanf(s,"l%d:",&l)==1){
+ p->flags|=LABDEF;
+ p->l1=l;
+ p->size=0;
+ if(!secok) p->flags|=BARRIER;
+ return;
+ }
+
+ if(!secok){
+ p->flags|=BARRIER;
+ return;
+ }
+
+ if(!isspace(*s)){
+ p->flags=BARRIER;
+ return;
+ }
+ while(isspace(*s))
+ s++;
+ for(e=s;isalpha(*e);e++);
+
+ for(i=0;i<sizeof(inst)/sizeof(inst[0]);i++){
+ if(!strncmp(s,inst[i],e-s)){
+ while(isspace(*e)) e++;
+ if(*e==0){
+ p->size=1;
+ return;
+ }
+ p->size=2;
+ if(sscanf(e,"l%d",&l)==1){
+ p->flags|=LABUSE;
+ p->l1=l;
+ }
+ if(*s=='b'||!strncmp(s,"jmp",3)){
+ p->flags|=BRANCH;
+ }
+ return;
+ }
+ }
+ p->flags=BARRIER;
+}
+
+static int nlab;
+
+#define SECTION "\tsection\ttext\n"
+
+void add_header(line *after)
+{
+ nlab=new_label();
+ line *new;
+ new=new_line();
+ new->flags=LABDEF;
+ new->l1=nlab;
+ new->code=mymalloc(16); /* TODO */
+ sprintf(new->code,"x%d:\n",nlab);
+ insert_line(after,new);
+ new=new_line();
+ new->flags=BARRIER;
+ new->code=mymalloc(strlen(SECTION)+1);
+ strcpy(new->code,SECTION);
+ insert_line(after,new);
+}
+
+void add_ret(line *after)
+{
+ line *new=new_line();
+ new->size=1;
+ new->flags=BARRIER;
+ new->code=mymalloc(8); /*TODO*/
+ strcpy(new->code,"\trts\n");
+ insert_line(after,new);
+}
+
+void add_jsr(line *after)
+{
+ line *new=new_line();
+ new->flags=LABUSE;
+ new->size=3;
+ new->l1=nlab;
+ new->code=mymalloc(24); /* TODO */
+ sprintf(new->code,"\tjsr\tx%d\n",nlab);
+ insert_line(after,new);
+}
diff --git a/machines/m65/machine.c b/machines/m65/machine.c
new file mode 100644
index 0000000..45819f1
--- /dev/null
+++ b/machines/m65/machine.c
@@ -0,0 +1,5163 @@
+/* MEGA65 45GS02 backend for vbcc
+ (c) Volker Barthelmann 2020
+ (c) Paul Gardner-Stephen 2020
+
+*/
+
+#include "supp.h"
+#include "vbc.h"
+
+#include <math.h>
+
+static char FILE_[]=__FILE__;
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc 45GS02 (MEGA65) code-generator V0.1 (c) in 2020 by Volker Barthelmann, Paul Gardner-Stephen";
+
+/* Commandline-flags the code-generator accepts:
+ 0: just a flag
+ VALFLAG: a value must be specified
+ STRINGFLAG: a string can be specified
+ FUNCFLAG: a function will be called
+ apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]={0,0,
+ VALFLAG,0,0,
+ 0,0,
+ VALFLAG,VALFLAG,0,0,
+ VALFLAG,0,0,0,
+ 0,0,0,
+ 0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+ they collide with the frontend */
+char *g_flags_name[MAXGF]={"std-syntax","no-rax",
+ "volatile-regs","ieee","no-peephole",
+ "cbmascii","softstack",
+ "reg-args","int-args","mainargs","no-bank-vars",
+ "common-banknr","btmp-zpage","oldfp","large",
+ "glob-acc","avoid-bank-switch","manual-banking",
+ "atascii","65c02"};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. will be initialized in init_cg(),
+ register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+ estimated cost-saving can be obtained by several registers, the
+ one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__interrupt","__zpage","__nocpr",0};
+
+#define INTERRUPT 1
+#define ZPAGE 2
+#define NOCOMPRESS 4
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+#define STDSYNTAX (g_flags[0]&USEDFLAG)
+#define NORAX (g_flags[1]&USEDFLAG)
+#define VOL_GPRS ((g_flags[2]&USEDFLAG)?g_flags_val[2].l:NUM_GPRS/2)
+#define IEEE (g_flags[3]&USEDFLAG)
+#define NOPEEP (g_flags[4]&USEDFLAG)
+#define CBMASCII (g_flags[5]&USEDFLAG)
+#define SOFTSTACK (g_flags[6]&USEDFLAG)
+#define GPR_ARGS ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:8)
+#define MAINARGS (g_flags[9]&USEDFLAG)
+#define NOBANKVARS (g_flags[10]&USEDFLAG)
+#define COMMONBANK ((g_flags[11]&USEDFLAG)?g_flags_val[11].l:0)
+#define BIGZPAGE (g_flags[12]&USEDFLAG)
+#define OLDFP (g_flags[13]&USEDFLAG)
+#define LARGE (g_flags[14]&USEDFLAG)
+#define GLOBACC (g_flags[15]&USEDFLAG)
+#define NOSWITCH (g_flags[16]&USEDFLAG)
+#define NOBANKING (g_flags[17]&USEDFLAG)
+#define ATASCII (g_flags[18]&USEDFLAG)
+#define C02 (g_flags[19]&USEDFLAG)
+
+
+
+#define STR_NEAR "near"
+#define STR_FAR "far"
+#define STR_HUGE "huge"
+
+#define PLA (-1)
+#define JMPIND (-2)
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isacc(x) (isreg(x)&&(p->x.reg==ra||p->x.reg==rax))
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+#define isptr(r) ((r)>=FIRST_PAIR&&(r)<=LAST_PAIR)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"ora","eor","and"};
+static char *arithmetics[]={"slw","srw","adc","sbc","mullw","divw","mod"};
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]= {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,2,4,8,4,4,4,0,2,3,3,0,0,0,1,0};
+static char *mregnames[MAXR+1];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","char","short","int","long","long long",
+ "float","double","long double","void",
+ "near-pointer","far-pointer","huge-pointer",
+ "array","struct","union","enum","function"};
+
+
+/* used to initialize regtyp[] */
+static struct Typ ityp={INT},ctyp={CHAR},ftyp={FLOAT},lltyp={LLONG};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+ "__m65__",
+ "__SIZE_T_INT",
+ "__bank(x)=__vattr(\"bank(\"#x\")\")",
+ "__far=__attr(\"far\")",
+ "__near=__attr(\"near\")",
+ "__huge=__attr(\"huge\")",
+ 0};
+
+/* special registers */
+static int ra=1, rx=2, ry=3, rz=4, sp1=5,sp2=6,sp=7,fp,fp1,fp2;
+static int t4=LAST_GPR,t3=LAST_GPR-1,t2=LAST_GPR-2,t1=LAST_GPR-3;
+static int rax=8;
+static int raxyz=9;
+static int yval;
+#define NOVAL 1000
+
+static int t1,t2,f1,f2; /*tODO: remove*/
+
+static int pushedacc,pushedx,nopeep,cbmascii,atascii,ieee;
+static int c02,noy;
+static int has_inc_a=1; // MEGA65 has INC A / INA instruction
+static int has_zero_reg=0;
+static char *jmpinst;
+static int pass;
+static int libsave;
+static struct rpair rp2;
+static int cbank;
+static Var bankv;
+static int bankvoffset;
+static int bankcnum;
+static obj zstore;
+static int zstoreflag;
+
+#define SECLEN 128
+char *use_sec;
+int use_bank=-1;
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* perhaps provide version with 8bit int? */
+#define ISCHAR(t) ((t&NQ)==CHAR)
+#define ISSHORT(t) ((t&NQ)==SHORT||(t&NQ)==INT||(t&NQ)==POINTER)
+#define ISFPOINTER(t) ((t&NQ)==FPOINTER)
+#define ISLONG(t) ((t&NQ)==LONG)
+#define ISLLONG(t) ((t&NQ)==LLONG)
+
+#define ISIDX(r) (r==rx||r==rz)
+
+/* am */
+#define IMM_IND 1
+#define GPR_IND 2
+#define ABS_IND 3
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\tsection\ttext",
+ *dataname="\tsection\tdata",
+ *bssname="\tsection\tbss",
+ *rodataname="\tsection\trodata";
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+/* variables to calculate the size and partitioning of the stack-frame
+ in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+
+static long localsize,rsavesize,rscnt,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+ stack-pointer; we use a layout like this:
+ ------------------------------------------------
+ | arguments to this function |
+ ------------------------------------------------
+ | caller-save registers [size=rsavesize] |
+ ------------------------------------------------
+ | local variables [size=localsize] |
+ ------------------------------------------------
+ | arguments to called functions [size=argsize] |
+ ------------------------------------------------
+ All sizes will be aligned as necessary.
+ In the case of FIXED_SP, the stack-pointer will be adjusted at
+ function-entry to leave enough space for the arguments and have it
+ aligned to 16 bytes. Therefore, when calling a function, the
+ stack-pointer is always aligned to 16 bytes.
+ For a moving stack-pointer, the stack-pointer will usually point
+ to the bottom of the area for local variables, but will move while
+ arguments are put on the stack.
+
+ This is just an example layout. Other layouts are also possible.
+*/
+
+static int bank(Var *v)
+{
+ char *s=v->vattr;
+ int n,r;
+ if(!NOBANKING&&s&&(s=strstr(s,"bank("))){
+ if(sscanf(s+5,"%i",&n)==1)
+ return n;
+ }
+ return -1;
+}
+
+static void ebank(FILE *f,int b)
+{
+ if(b>=0) emit(f,"%d",b);
+ emit(f,"\n");
+}
+
+static long real_offset(struct obj *o)
+{
+ long off=zm2l(o->v->offset);
+ if(off<0){
+ /* function parameter */
+ off=localsize+rsavesize-off-zm2l(maxalign);
+ }
+
+ off+=argsize;
+ off+=zm2l(o->val.vmax);
+ return off;
+}
+
+/* Initializes an addressing-mode structure and returns a pointer to
+ that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ am.offset=offset;
+ return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+ char *sec;
+ if(v->tattr&ZPAGE){
+ emit(f,"\tsection\tzpage\n");
+ }else{
+ if(!v->vattr) return 0;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return 0;
+ sec+=strlen("section(");
+ emit(f,"\tsection\t");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ }
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+
+
+#define chk_coll(x) do{if((x)==r||(x)==r1||(x)==r2) return 0; \
+ if(reg_pair((x),&rp)&&(rp.r1==r||rp.r2==r)) return 0;}while(0)
+
+static int scratch(IC *p,int r)
+{
+ int r1,r2;
+ if(!p) return 1;
+ if(reg_pair(r,&rp)){
+ r1=rp.r1;
+ r2=rp.r2;
+ }else{
+ r1=0;
+ r2=0;
+ }
+ if(isreg(z)&&p->z.reg==r){
+ if(!(p->q2.flags®))
+ return 1;
+ if(p->q2.reg==r||p->q2.reg==r1||p->q2.reg==r2)
+ return 0;
+ if(reg_pair(p->q2.reg,&rp))
+ if(rp.r1==r||rp.r2==r)
+ return 0;
+ return 1;
+ }
+ while(p){
+ if(p->code==LABEL||p->code==CALL)
+ return 0;
+ if(p->code>=BEQ&&p->code<=BRA)
+ return 0;
+ if(p->code==FREEREG||p->code==ALLOCREG){
+ if(p->q1.reg==r)
+ return 1;
+ if(reg_pair(p->q1.reg,&rp)&&(rp.r1==r||rp.r2==r))
+ return 1;
+ }
+ if(p->q1.am) chk_coll(p->q1.am->base);
+ if(p->q2.am) chk_coll(p->q2.am->base);
+ if(p->z.am) chk_coll(p->z.am->base);
+ if(p->q1.flags®) chk_coll(p->q1.reg);
+ if(p->q2.flags®) chk_coll(p->q2.reg);
+ if(p->z.flags®){
+ if(p->z.flags&DREFOBJ)
+ chk_coll(p->z.reg);
+ else{
+ if(p->z.reg==r)
+ return 1;
+ if(reg_pair(p->z.reg,&rp)&&(rp.r1==r||rp.r2==r))
+ return 1;
+ }
+ }
+
+ p=p->next;
+ }
+ return 1;
+}
+
+static int rsavecur;
+static int in_isr;
+
+static int get_reg(FILE *f,IC *p,int t)
+{
+ int r,r1,r2,pass,flag;
+
+ for(pass=0;pass<5;pass++){
+ for(r=MAXR;r>sp;r--){
+ if(reg_pair(r,&rp)){
+ r1=rp.r1;
+ r2=rp.r2;
+ }else{
+ r1=0;
+ r2=0;
+ }
+ if((pass==0||pass==3)&&(!regscratch[r]||in_isr))
+ continue;
+ if(pass<3){
+ if(regs[r]) continue;
+ if(r1&&(regs[r1]||regs[r2])) continue;
+ }
+ if(pass==2&&!(regs[r]&4))
+ continue;
+ if((p->q1.flags®)&&(p->q1.reg==r||p->q1.reg==r1||p->q1.reg==r2)) continue;
+ if((p->q2.flags®)&&(p->q2.reg==r||p->q2.reg==r1||p->q2.reg==r2)) continue;
+ if((p->z.flags®)&&(p->z.reg==r||p->z.reg==r1||p->z.reg==r2)) continue;
+ if(regok(r,t,1)){
+ flag=8;
+ if(regs[r]){
+ flag|=2;
+ if(p->code==COMPARE||p->code==TEST)
+ ierror(0);
+ if(regs[ra]){
+ emit(f,"\ttay\n");
+ yval=NOVAL;
+ }
+ if(r1){
+ emit(f,"\tlda\t%s\n",mregnames[r1]);
+ emit(f,"\tpha\n");
+ emit(f,"\tlda\t%s\n",mregnames[r2]);
+ emit(f,"\tpha\n");
+ }else{
+ emit(f,"\tlda\t%s\n",mregnames[r]);
+ emit(f,"\tpha\n");
+ }
+ if(regs[ra])
+ emit(f,"\ttya\n");
+ }
+ if(r1){
+ regs[r1]|=flag;
+ regs[r2]|=flag;
+ }
+ regs[r]|=flag;
+ regused[r]=1;
+ regused[r1]=1;
+ regused[r2]=1;
+ return r;
+ }
+ }
+ }
+ pric2(stdout,p);
+ ierror(0);
+}
+
+static void get_acc(FILE *f, IC *p,int t)
+{
+ int r;
+ if(isacc(z)) return;
+ t&=NQ;
+ if(ISCHAR(t)){
+ if(1/*!isreg(q1)||(p->q1.reg!=ra&&p->q1.reg!=rax)*/){
+ if((regs[ra]||regs[rax])&&!scratch(p,ra)&&!pushedacc){
+ if(optsize||(regs[t1]&®s[t2]&®s[t3]&®s[t4])){
+ emit(f,"\tpha\n");
+ pushedacc=-1;
+ }else{
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ pushedacc=r;
+ }
+ }
+ }
+ }else{
+ if(1/*!isreg(q1)||p->q1.reg!=rax*/){
+ if((regs[ra]||regs[rax])&&(!scratch(p,ra)||!scratch(p,rax))&&!pushedacc){
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ pushedacc=r;
+ }
+ if((regs[rx]||regs[rax])&&!scratch(p,rax)&&!pushedx){
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tstx\t%s\n",mregnames[r]);
+ pushedx=r;
+ }
+ }
+ }
+}
+
+static int cmp_get_acc(FILE *f,IC *p,IC *branch)
+{
+ if(!regs[ra]&&!regs[rax])
+ return 0;
+ if(branch==0&&pushedacc)
+ return 0;
+ if(branch&&isreg(q1)&&(p->q1.reg==ra||p->q1.reg==rax))
+ if(branch->code==BEQ||branch->code==BNE||(p->typf&UNSIGNED))
+ return 0;
+ if(scratch(p,ra))
+ return 0;
+ if(!regs[rx]&&!regs[rax]){
+ emit(f,"\ttax\n");
+ pushedacc=rx;
+ }
+ emit(f,"\tpha\n");
+ pushedacc=-1;
+ return pushedacc;
+}
+
+static void reload_acc_opt(FILE *f,IC *p)
+{
+ if(pushedacc==0) return;
+ if(pushedacc>0){
+ while(p){
+ if(p->code!=FREEREG) break;
+ if(p->q1.reg==ra||p->q1.reg==rax){
+ pushedacc=0;
+ return;
+ }
+ p=p->next;
+ }
+ }
+ if(pushedacc==-1)
+ emit(f,"\tpla\n");
+ else if(pushedacc==rx)
+ emit(f,"\ttxa\n");
+ else if(pushedacc==ry)
+ emit(f,"\ttya\n");
+ else if(pushedacc){
+ emit(f,"\tlda\t%s\n",mregnames[pushedacc]);
+ regs[pushedacc]&=~8;
+ }
+ pushedacc=0;
+}
+
+static void reload_acc(FILE *f)
+{
+ reload_acc_opt(f,0);
+}
+
+static void push(int i)
+{
+ pushed-=i;
+ if(pushed<maxpushed)
+ maxpushed=pushed;
+}
+
+static void pop(int i)
+{
+ pushed+=i;
+ if(pushed>0) ierror(0);
+}
+
+static int indirect(obj *o)
+{
+ if((o->flags&(DREFOBJ|KONST))==DREFOBJ)
+ return 1;
+ if((o->flags&(REG|VAR))!=VAR){
+ if(o->reg==ra||ISIDX(o->reg)||o->reg==rax)
+ return 1;
+ return 0;
+ }
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)
+ return 1;
+ return 0;
+}
+
+void convfloat(void)
+{
+}
+
+void sety(FILE *f,int val)
+{
+ if(yval==val)
+ return;
+ if(val-yval==1)
+ emit(f,"\tiny\n");
+ else if(yval-val==1)
+ emit(f,"\tdey\n");
+ else{
+ emit(f,"\tldy\t#%d\n",val);
+ if(val<0||val>255)
+ ierror(0);
+ }
+ yval=val;
+}
+
+static void cnv_fp(void)
+{
+ double d,mant;
+ int exp;
+ unsigned long t;
+
+ if(ieee){
+ vfloat=zld2zf(vldouble);
+ memcpy((void*)&vmax,(void*)&vfloat,4);
+ }else{
+ d=zld2d(vldouble);
+ mant=frexp(d,&exp);
+ exp=(exp+127)&255;
+ t=((unsigned long)(mant*8388608))&0xffffff;
+ t|=((long)exp)<<24;
+
+ t=((t&0xff)<<24)|((t&0xff00)<<8)|((t&0xff0000)>>8)|((t&0xff000000)>>24);
+ vmax=l2zm((long)t);
+ if(mant==0&&d==0) vmax=Z0;
+ }
+}
+
+static void emit_ieee(FILE *f,union atyps *p,int t)
+{
+ unsigned char *ip=(unsigned char *)&p->vdouble;
+ emit(f,"0x%02x%02x,0x%02x%02x",ip[1],ip[0],ip[3],ip[2]);
+ if(t==DOUBLE||t==LDOUBLE)
+ emit(f,",0x%02x%02x,0x%02x%02x",ip[5],ip[4],ip[7],ip[6]);
+ emit(f,"\n");
+}
+
+static void emit_lobyte(FILE *f,obj *o,int t)
+{
+ if(o->flags&KONST){
+ if(o->flags&DREFOBJ){
+ eval_const(&o->val,o->dtyp);
+ emit(f,"%d",zm2l(vmax));
+ }else{
+ eval_const(&o->val,t);
+ if(ISFLOAT(t)) cnv_fp();
+ emit(f,"#%d",zm2l(vmax)&255);
+ }
+ }else if(o->flags&VARADR){
+ emit(f,"#<(");
+ emit_obj(f,o,t);
+ emit(f,")");
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ if(!reg_pair(o->reg,&rp))
+ emit(f,"%s",mregnames[o->reg]);
+ else
+ emit(f,"%s",mregnames[rp.r1]);
+ }else{
+ if(c02&&(o->flags&(DREFOBJ|KONST))==DREFOBJ) noy=1;
+ emit_obj(f,o,t);
+ noy=0;
+ }
+}
+
+static void emit_hibyte(FILE *f,obj *o,int t)
+{
+ if(o->flags&KONST){
+ if(o->flags&DREFOBJ){
+ eval_const(&o->val,o->dtyp);
+ emit(f,"%d",zm2l(vmax)+1);
+ }else{
+ eval_const(&o->val,t);
+ if(ISFLOAT(t)) cnv_fp();
+ emit(f,"#%d",(zm2l(vmax)>>8)&255);
+ }
+ }else if(o->flags&VARADR){
+ emit(f,"#>(");
+ emit_obj(f,o,t);
+ emit(f,")");
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg>=FIRST_BIG&&o->reg<=LAST_BIGP){
+ emit(f,"%s+1",mregnames[o->reg]);
+ }else{
+ if(!reg_pair(o->reg,&rp))
+ ierror(0);
+ emit(f,"%s",mregnames[rp.r2]);
+ }
+ }else{
+ if(o->flags&VARADR)
+ emit(f,"#");
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmadd(o->val.vmax,Z1);
+ emit_obj(f,o,t);
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmsub(o->val.vmax,Z1);
+ }
+}
+
+static void emit_byte3(FILE *f,obj *o,int t)
+{
+ if(o->flags&KONST){
+ if(o->flags&DREFOBJ){
+ eval_const(&o->val,o->dtyp);
+ emit(f,"%d",zm2l(vmax)+2);
+ }else{
+ eval_const(&o->val,t);
+ if(ISFLOAT(t)) cnv_fp();
+ emit(f,"#%d",(zm2l(vmax)>>16)&255);
+ }
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ emit(f,"%s+2",mregnames[o->reg]);
+ }else if(o->flags&VARADR){
+ emit(f,"#%d",bank(o->v));
+ }else{
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmadd(o->val.vmax,l2zm(2L));
+ emit_obj(f,o,t);
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmsub(o->val.vmax,l2zm(2L));
+ }
+}
+
+static void emit_byte4(FILE *f,obj *o,int t)
+{
+ if(o->flags&KONST){
+ if(o->flags&DREFOBJ){
+ eval_const(&o->val,o->dtyp);
+ emit(f,"%d",zm2l(vmax)+3);
+ }else{
+ eval_const(&o->val,t);
+ if(ISFLOAT(t)) cnv_fp();
+ emit(f,"#%d",(zm2l(vmax)>>24)&255);
+ }
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ emit(f,"%s+3",mregnames[o->reg]);
+ }else{
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmadd(o->val.vmax,l2zm(3L));
+ emit_obj(f,o,t);
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmsub(o->val.vmax,l2zm(3L));
+ }
+}
+
+static void do_lobyte(FILE *f,char *s,obj *o,int type)
+{
+ if(o->am){
+ if(o->am->flags==IMM_IND)
+ sety(f,o->am->offset);
+ else if(o->am->flags==GPR_IND||o->am->flags==ABS_IND){
+ if(o->am->idx==ra)
+ emit(f,"\ttay\n");
+ else{
+ if(ISIDX(o->am->idx)){
+ if(o->am->flags==GPR_IND){
+ emit(f,"\tpha\n");
+ emit(f,"\tt%sa\n",mregnames[o->am->idx]);
+ emit(f,"\ttay\n");
+ emit(f,"\tpla\n");
+ }
+ }else
+ emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+ }
+ yval=NOVAL;
+ }else
+ ierror(0);
+ }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+ if(!c02) sety(f,0);
+ }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+ sety(f,(int)real_offset(o));
+ }
+ emit(f,"\t%s\t",s);
+ emit_lobyte(f,o,type);
+ emit(f,"\n");
+}
+
+static void do_hibyte(FILE *f,char *s,obj *o,int type)
+{
+ int ami=0;
+ if(o->am){
+ if(o->am->flags==IMM_IND)
+ sety(f,o->am->offset+1);
+ else if(o->am->flags==ABS_IND){
+ if(o->am->offset==ra)
+ emit(f,"\ttay\n");
+ else
+ emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+ o->am->offset++;ami=1;
+ yval=NOVAL;
+ }else
+ ierror(0);
+ }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+ sety(f,1);
+ }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+ sety(f,(int)real_offset(o)+1);
+ }
+ emit(f,"\t%s\t",s);
+ emit_hibyte(f,o,type);
+ emit(f,"\n");
+ if(ami) o->am->offset--;
+}
+
+static void do_byte3(FILE *f,char *s,obj *o,int type)
+{
+ int ami=0;
+ if(o->am){
+ if(o->am->flags==IMM_IND)
+ sety(f,o->am->offset+2);
+ else if(o->am->flags==ABS_IND){
+ if(o->am->offset==ra)
+ emit(f,"\ttay\n");
+ else
+ emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+ yval=NOVAL;
+ o->am->offset+=2;ami=1;
+ }else
+ ierror(0);
+ }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+ sety(f,2);
+ }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+ sety(f,(int)real_offset(o)+2);
+ }
+ emit(f,"\t%s\t",s);
+ emit_byte3(f,o,type);
+ emit(f,"\n");
+ if(ami) o->am->offset-=2;
+}
+
+static void do_byte4(FILE *f,char *s,obj *o,int type)
+{
+ int ami=0;
+ if(o->am){
+ if(o->am->flags==IMM_IND)
+ sety(f,o->am->offset+3);
+ else if(o->am->flags==ABS_IND){
+ if(o->am->offset==ra)
+ emit(f,"\ttay\n");
+ else
+ emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+ yval=NOVAL;
+ o->am->offset+=3;ami=1;
+ }else
+ ierror(0);
+ }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+ sety(f,3);
+ }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+ sety(f,(int)real_offset(o)+3);
+ }
+ emit(f,"\t%s\t",s);
+ emit_byte4(f,o,type);
+ emit(f,"\n");
+ if(ami) o->am->offset-=3;
+}
+
+static void load_lobyte(FILE *f,obj *o,int t)
+{
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg==ra||o->reg==rax)
+ return;
+ if(o->reg==rx){
+ emit(f,"\ttxa\n");
+ return;
+ }
+ }
+ do_lobyte(f,"lda",o,t);
+}
+
+static void load_hibyte(FILE *f,obj *o,int t)
+{
+ if((o->flags®)&&(o->reg==rx||o->reg==rax))
+ emit(f,"\ttxa\n");
+ else
+ do_hibyte(f,"lda",o,t);
+}
+
+static void store_lobyte(FILE *f,obj *o,int t)
+{
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg==ra||o->reg==rax)
+ return;
+ if(o->reg==rx){
+ emit(f,"\ttax\n");
+ return;
+ }
+ }
+ do_lobyte(f,"sta",o,t);
+}
+
+static void store_hibyte(FILE *f,obj *o,int t)
+{
+ if((o->flags®)&&(o->reg==rx||o->reg==rax))
+ emit(f,"\ttax\n");
+ else
+ do_hibyte(f,"sta",o,t);
+}
+
+static void load_acc(FILE *f,obj *o,int type)
+{
+ if((o->flags®)&&(o->reg==ra||o->reg==rax))
+ return;
+ if(!ISCHAR(type)){
+ if(indirect(o)){
+ do_hibyte(f,"lda",o,type);
+ emit(f,"\ttax\n");
+ }else
+ do_hibyte(f,"ldx",o,type);
+ }
+ if((o->flags&(REG|DREFOBJ))==REG&&o->reg==rx)
+ emit(f,"\ttxa\n");
+ else
+ do_lobyte(f,"lda",o,type);
+}
+
+static void store_acc(FILE *f,obj *o,int type)
+{
+ if((o->flags&(DREFOBJ|KONST))==DREFOBJ&&((!(o->flags®))||!isptr(o->reg))){
+ ierror(0);
+ }
+ if((o->flags®)&&(o->reg==ra||o->reg==rax))
+ return;
+ if((o->flags®)&&o->reg==rx){
+ emit(f,"\ttax\n");
+ return;
+ }
+ store_lobyte(f,o,type);
+ if(!ISCHAR(type)){
+ if(indirect(o)){
+ /*TODO: save accu */
+ emit(f,"\ttxa\n");
+ store_hibyte(f,o,type);
+ }else
+ do_hibyte(f,"stx",o,type);
+ }
+}
+
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+ static obj ro;
+ if(ISIDX(r)&&!indirect(o)){
+ static char ldr[4]="ldr";
+ ldr[2]=mregnames[r][0];
+ do_lobyte(f,ldr,o,type);
+ return;
+ }
+ ro.flags=REG;
+ ro.reg=r;
+ load_lobyte(f,o,type);
+ store_lobyte(f,&ro,type);
+ if(!ISCHAR(type)){
+ load_hibyte(f,o,type);
+ store_hibyte(f,&ro,type);
+ }
+}
+
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+ static obj ro;
+ if(ISIDX(r)){
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg==r)
+ return;
+ if(o->reg==ra){
+ emit(f,"\tt%sa\n",mregnames[r]);
+ return;
+ }
+ }
+ if(!indirect(o)){
+ static char str[4]="str";
+ str[2]=mregnames[r][0];
+ do_lobyte(f,str,o,type);
+ return;
+ }
+ }
+ ro.flags=REG;
+ ro.reg=r;
+ if(r!=ra&&r!=rax)
+ load_acc(f,&ro,type);
+ store_acc(f,o,type);
+}
+
+static struct fpconstlist {
+ struct fpconstlist *next;
+ int label;
+ int t;
+ union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+ struct fpconstlist *p=firstfpc;
+ t&=NQ;
+ if(t==LDOUBLE) t=DOUBLE;
+ for(p=firstfpc;p;p=p->next){
+ if(t==p->t){
+ eval_const(&p->val,t);
+ if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+ if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+ if(t==LONG&&zmeqto(vmax,zl2zm(o->val.vlong))) return p->label;
+ if(t==LLONG&&zmeqto(vmax,zll2zm(o->val.vllong))) return p->label;
+ }
+ }
+ p=mymalloc(sizeof(struct fpconstlist));
+ p->next=firstfpc;
+ p->t=t;
+ p->label=++label;
+ p->val=o->val;
+ firstfpc=p;
+ return p->label;
+}
+
+/* generate code to load the address of a local variable into register r */
+static void load_laddr(FILE *f,int r,struct obj *o)
+{
+ long l=real_offset(o);
+ /* assumes acc is available */
+ if(!reg_pair(r,&rp)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[fp]);
+ if(l!=0)
+ emit(f,"\tclc\n");
+ if(l&255)
+ emit(f,"\tadc\t#%ld\n",l&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[fp2]);
+ if(l!=0)
+ emit(f,"\tadc\t#%ld\n",(l>>8)&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int t)
+{
+ if(o->flags&DREFOBJ){
+ o->flags&=~DREFOBJ;
+ load_reg(f,r,o,POINTER);
+ o->flags|=DREFOBJ;
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ if(!reg_pair(r,&rp)) ierror(0);
+ emit(f,"\tlda\t#>%s\n",mregnames[o->reg]);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tlda\t#<%s\n",mregnames[o->reg]);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ }else if(o->flags&VAR){
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+ load_laddr(f,r,o);
+ }else{
+ o->flags|=VARADR;
+ load_reg(f,r,o,POINTER);
+ o->flags&=~VARADR;
+ }
+ }else if((o->flags&(KONST|DREFOBJ))==KONST){
+ int l=addfpconst(o,t);
+ if(!ieee) ierror(0);
+ if(!reg_pair(r,&rp)) ierror(0);
+ emit(f,"\tlda\t#>%s%d\n",labprefix,l);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tlda\t#<%s%d\n",labprefix,l);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ }else
+ ierror(0);
+}
+
+
+/* Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+
+static void incmem(FILE *f,obj *o,int t,int op,int x)
+{
+ int i,idx=0;
+ char *s;
+ if((o->flags&(REG|DREFOBJ))==REG&&ISIDX(o->reg)){
+ static char buf[4]=" ";
+ idx=1;s=buf;
+ if(op==ADD){s[0]='i';s[1]='n';}else{s[0]='d';s[1]='e';}
+ s[2]=mregnames[o->reg][0];
+ }else if(op==ADD)
+ s="inc";
+ else if(op==SUB)
+ s="dec";
+ else if(op==LSHIFT)
+ s="asl";
+ else if(op==RSHIFT&&(t&UNSIGNED))
+ s="clc\n\tror";
+ else if(op==RSHIFT){
+ s="cmp\t#128\n\tror";
+ }else
+ ierror(0);
+ if(ISCHAR(t)){
+ for(i=0;i<x;i++){
+ if(idx){
+ emit(f,"\t%s\n",s);
+ }else{
+ emit(f,"\t%s\t",s);
+ emit_obj(f,o,t);
+ emit(f,"\n");
+ }
+ }
+ }else{
+ for(i=0;i<x;i++){
+ if(op==SUB){
+ /* caller mus make sure accu is available */
+ load_lobyte(f,o,t);
+ emit(f,"\tbne\t%s%d\n",labprefix,++label);
+ emit(f,"\tdec\t");
+ emit_hibyte(f,o,t);
+ emit(f,"\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tdec\t");
+ emit_lobyte(f,o,t);
+ emit(f,"\n");
+ }else if(op==ADD){
+ emit(f,"\t%s\t",s);
+ emit_lobyte(f,o,t);
+ emit(f,"\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,++label);
+ emit(f,"\t%s\t",s);
+ emit_hibyte(f,o,t);
+ emit(f,"\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ }else if(op==LSHIFT){
+ // 4510 / 45GS02 have ASW/ROW operations
+ // for left-shifting 16-bit values
+
+ emit(f,"\tasw\t");
+ emit_obj(f,o,t);
+ emit(f,"\n");
+
+ }else if(op==RSHIFT&&(t&UNSIGNED)){
+ emit(f,"\tclc\n");
+ emit(f,"\tror\t");
+ emit_hibyte(f,o,t);
+ emit(f,"\n");
+ emit(f,"\tror\t");
+ emit_lobyte(f,o,t);
+ emit(f,"\n");
+ }else if(op==RSHIFT){
+ load_hibyte(f,o,t);
+ emit(f,"\tcmp\t#128\n");
+ emit(f,"\tror\t");
+ emit_hibyte(f,o,t);
+ emit(f,"\n");
+ emit(f,"\tror\t");
+ emit_lobyte(f,o,t);
+ emit(f,"\n");
+ }else{
+ printf("op=%d\n",op);
+ ierror(0);
+ }
+ }
+ }
+}
+
+static void preload_obj(FILE *f,IC *p,obj *o)
+{
+ int r;long of;
+
+ if((p->typf&VOLATILE)||(p->typf2&VOLATILE)||
+ ((p->q1.flags&DREFOBJ)&&(p->q1.dtyp&(VOLATILE|PVOLATILE)))||
+ ((p->q2.flags&DREFOBJ)&&(p->q2.dtyp&(VOLATILE|PVOLATILE)))||
+ ((p->z.flags&DREFOBJ)&&(p->z.dtyp&(VOLATILE|PVOLATILE))))
+ emit(f,"; volatile barrier\n");
+
+
+ if((o->flags&(VAR|REG))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)&&(of=real_offset(o))+zm2l(szof(o->v->vtyp))>255){
+ r=get_reg(f,p,POINTER);
+ if(o->flags&DREFOBJ)
+ get_acc(f,p,INT);
+ else
+ cmp_get_acc(f,p,0);
+ if(!reg_pair(r,&rp)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[fp1]);
+ emit(f,"\tclc\n");
+ if(of&0xff)
+ emit(f,"\tadc\t#%ld\n",of&0xff);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[fp2]);
+ if(1/*of&0xff00*/)
+ emit(f,"\tadc\t#%ld\n",(of>>8)&0xff);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ o->flags|=REG;
+ o->reg=r;
+ if(o->flags&DREFOBJ){
+ if(!c02) sety(f,0);
+ emit(f,"\tlda\t(%s)%s\n",mregnames[r],c02?"":",y");
+ emit(f,"\ttxa\n");
+ sety(f,1);
+ emit(f,"\tlda\t(%s),y\n",mregnames[r]);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tstx\t%s\n",mregnames[rp.r1]);
+ }else{
+ o->flags|=DREFOBJ;
+ o->dtyp=POINTER;
+ }
+ }
+
+ if((o->flags&(DREFOBJ|KONST))==DREFOBJ&&(!(o->flags®)||!isptr(o->reg))&&(!(o->flags&VAR)||!(o->v->tattr&ZPAGE))&&!ISFPOINTER(o->dtyp)){
+ cmp_get_acc(f,p,0);
+ r=get_reg(f,p,POINTER);
+ o->flags&=~DREFOBJ;
+ load_reg(f,r,o,POINTER);
+ o->flags|=REG|DREFOBJ;
+ o->reg=r;
+ }
+}
+
+static void far_copy(FILE *f,IC *p)
+{
+ int b;long l;
+ get_acc(f,p,INT);
+ if(p->code==PUSH){
+ if(!reg_pair(LAST_PAIR,&rp)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ if(pushed) emit(f,"\tclc\n");
+ if(pushed&0xff) emit(f,"\tadc\t#%d\n",(pushed&0xff));
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+ if(pushed) emit(f,"\tadc\t#%d\n",((pushed>>8)&0xff));
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ pushed+=zm2l(p->q2.val.vmax);
+ emit(f,"\tldx\t#%d\n",bankcnum);
+ }else if(p->z.flags&DREFOBJ){
+ if(!reg_pair(LAST_PAIR,&rp)) ierror(0);
+ p->z.flags&=~DREFOBJ;
+ load_lobyte(f,&p->z,FPOINTER);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ load_hibyte(f,&p->z,FPOINTER);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ if(indirect(&p->z)){
+ do_byte3(f,"lda",&p->z,FPOINTER);
+ emit(f,"\ttax\n");
+ }else
+ do_byte3(f,"ldx",&p->z,FPOINTER);
+ }else{
+ load_address(f,LAST_PAIR,&p->z,POINTER);
+ b=bank(p->z.v);
+ emit(f,"\tldx\t#%d\n",b>=0?b:bankcnum);
+ }
+ if(p->q1.flags&DREFOBJ){
+ if(!reg_pair(LAST_PAIR-1,&rp)) ierror(0);
+ p->q1.flags&=~DREFOBJ;
+ load_lobyte(f,&p->q1,FPOINTER);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ load_hibyte(f,&p->q1,FPOINTER);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ if(indirect(&p->q1)){
+ do_byte3(f,"lda",&p->q1,FPOINTER);
+ emit(f,"\ttay\n");
+ }else
+ do_byte3(f,"ldy",&p->q1,FPOINTER);
+ }else{
+ load_address(f,LAST_PAIR-1,&p->q1,POINTER);
+ b=bank(p->q1.v);
+ sety(f,b>=0?b:bankcnum);
+ }
+ l=zm2l(p->q2.val.vmax);
+ emit(f,"\tlda\t#%d\n",(l>>8)&0xff);
+ emit(f,"\tsta\t%s__bankcopy_len+1\n",idprefix);
+ emit(f,"\tlda\t#%d\n",(l)&0xff);
+ emit(f,"\tsta\t%s__bankcopy_len\n",idprefix);
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ emit(f,"\tjsr\t%s__bankcopy\n",idprefix);
+ yval=NOVAL;
+}
+
+static void load_far(FILE *f,IC *p,obj *o,int t)
+{
+ int pushed=0;
+ if(!(o->flags&DREFOBJ)) ierror(0);
+ o->flags&=~DREFOBJ;
+ t&=NQ;
+ if(zmeqto(sizetab[t],Z0)) return;
+ /*get_acc(f,p,INT);*/
+ if(pushedacc==t3||pushedacc==t4) ierror(0);
+ if(pushedx==t3||pushedx==t4) ierror(0);
+ if(regs[ra]||regs[rax]){
+ if(isacc(q1)||isacc(q2)||!isacc(z)){
+ pushed=1;
+ emit(f,"\tpha\n");
+ if(regs[rax]) emit(f,"\ttxa\n\tpha\n");
+ }
+ }
+ load_reg(f,LAST_PAIR,o,POINTER);
+ if(!indirect(o))
+ do_byte3(f,"ldy",o,CHAR);
+ else{
+ do_byte3(f,"lda",o,CHAR);
+ emit(f,"\ttay\n");
+ }
+ emit(f,"\tldx\t#%d\n",bankvoffset);
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ emit(f,"\tjsr\t%s__bankload%d\n",idprefix,(int)zm2l(sizetab[t]));
+ yval=NOVAL;
+ o->flags=VAR;
+ o->v=&bankv;
+ o->val.vmax=l2zm((long)bankvoffset);
+ bankvoffset+=zm2l(sizetab[t]);
+ if(pushed){
+ if(regs[rax]) emit(f,"\tpla\n\ttax\n");
+ emit(f,"\tpla\n");
+ }
+}
+
+static void load_banked(FILE *f,IC *p,obj *o,int t)
+{
+ int pushed=0,m;
+ if(o->flags&DREFOBJ) t=o->dtyp;
+ t&=NQ;
+ if(zmeqto(sizetab[t],Z0)) return;
+ /*get_acc(f,p,INT);*/
+ if(pushedacc==t3||pushedacc==t4) ierror(0);
+ if(pushedx==t3||pushedx==t4) ierror(0);
+ if(regs[ra]||regs[rax]){
+ if(isacc(q1)||isacc(q2)||!isacc(z)){
+ pushed=1;
+ emit(f,"\tpha\n");
+ if(regs[rax]||regs[rx]) emit(f,"\ttxa\n\tpha\n");
+ }
+ }
+ m=o->flags;
+ o->flags&=~DREFOBJ;
+ load_address(f,LAST_PAIR,o,POINTER);
+ o->flags=m;
+ emit(f,"\tldx\t#%d\n",bankvoffset);
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ sety(f,bank(o->v));
+ emit(f,"\tjsr\t%s__bankload%d\n",idprefix,(int)zm2l(sizetab[t]));
+ yval=NOVAL;
+ o->v=&bankv;
+ o->val.vmax=l2zm((long)bankvoffset);
+ bankvoffset+=zm2l(sizetab[t]);
+ if(pushed){
+ if(regs[rax]||regs[rx]) emit(f,"\tpla\n\ttax\n");
+ emit(f,"\tpla\n");
+ }
+}
+
+static void preload(FILE *f,IC *p)
+{
+ int r,mra=regs[ra],mrax=regs[rax];
+ int bq1=-1,bq2=-1,bz=-1,sb=-1,zbuf=0;
+
+ if(p->code==GETRETURN&&p->q1.reg==ra&&!regs[ra])
+ regs[ra]=1;
+
+ if(p->code==GETRETURN&&p->q1.reg==rax&&!regs[rax])
+ regs[rax]=1;
+
+ bankvoffset=0;
+
+ if(!NOBANKVARS){
+ if((p->q1.flags&(VAR|VARADR))==VAR) bq1=bank(p->q1.v);
+ if((p->q2.flags&(VAR|VARADR))==VAR) bq2=bank(p->q2.v);
+ if((p->z.flags&(VAR|VARADR))==VAR) bz=bank(p->z.v);
+
+ if((p->q1.flags&(VAR|VARADR))==(VAR|VARADR)){
+ r=bank(p->q1.v);
+ /*if(r>=0&&r!=cbank) ierror(0);*/
+ }
+
+ if((p->code==ASSIGN||p->code==PUSH)&&!zmleq(p->q2.val.vmax,l2zm(4L))){
+ if(p->q1.flags&DREFOBJ) preload_obj(f,p,&p->q1);
+ if(p->z.flags&DREFOBJ) preload_obj(f,p,&p->z);
+ return;
+ }
+
+ if(p->code!=CALL){
+ /* TODO: some optimizations possible */
+ if(bq1>=0&&bq1!=cbank){
+ if(cbank<0&&!NOSWITCH)
+ sb=bq1;
+ else
+ load_banked(f,p,&p->q1,q1typ(p));
+ }
+ if(bq2>=0&&bq2!=cbank){
+ if((bq2==sb||(cbank<0&&sb<0))&&!NOSWITCH)
+ sb=bq2;
+ else
+ load_banked(f,p,&p->q2,q2typ(p));
+ }
+ if(bz>=0&&bz!=cbank&&(p->z.flags&DREFOBJ)){
+ if((bz==sb||(cbank<0&&sb<0))||!NOSWITCH)
+ sb=bz;
+ else
+ load_banked(f,p,&p->z,ztyp(p));
+ }
+
+ if(sb>=0){
+ if(NOSWITCH) ierror(0);
+ sety(f,sb);
+ emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+ yval=NOVAL;
+ }
+ }
+ }
+
+ if((p->q1.flags&DREFOBJ)&&ISFPOINTER(p->q1.dtyp)&&p->code!=CALL) load_far(f,p,&p->q1,q1typ(p));
+ if((p->q2.flags&DREFOBJ)&&ISFPOINTER(p->q2.dtyp)) load_far(f,p,&p->q2,q2typ(p));
+
+ if(isacc(q2)){
+ static obj o;
+ int t=q2typ(p);
+ r=get_reg(f,p,t);
+ o.flags=REG;
+ o.reg=r;
+ store_acc(f,&o,t);
+ p->q2.reg=r;
+ }
+
+ if(p->code!=ADDRESS){
+ preload_obj(f,p,&p->q1);
+ if((p->q1.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+ (p->q2.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+ p->q1.v==p->q2.v){
+ p->q2.flags|=REG;
+ p->q2.reg=p->q1.reg;
+ }
+ if((p->q1.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+ (p->z.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+ p->q1.v==p->z.v){
+ p->z.flags|=REG;
+ p->z.reg=p->q1.reg;
+ }
+ }
+
+ preload_obj(f,p,&p->q2);
+ if((p->q2.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+ (p->z.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+ p->q2.v==p->z.v){
+ p->z.flags|=REG;
+ p->z.reg=p->q1.reg;
+ }
+
+
+ if((p->z.flags&DREFOBJ)&&ISFPOINTER(p->z.dtyp)) zbuf=1;
+ if((p->z.flags&(VAR|DREFOBJ))==VAR){
+ bz=bank(p->z.v);
+ if(bz>=0&&bz!=cbank) zbuf=1;
+ }
+
+ if(zbuf&&!NOBANKVARS){
+ zstore=p->z;
+ p->z.flags=VAR;
+ p->z.v=&bankv;
+ p->z.val.vmax=l2zm((long)bankvoffset);
+ zstoreflag=1;
+ /*bankvoffset+=zm2l(sizetab[p->typf&NQ]);*/
+ }else{
+ preload_obj(f,p,&p->z);
+
+ if(isreg(z)){
+ r=0;
+ if(p->q1.am&&p->q1.am->base==p->z.reg){
+ r=get_reg(f,p,POINTER);
+ cmp_get_acc(f,p,0);
+ if(!reg_pair(p->q1.am->base,&rp)) ierror(0);
+ if(!reg_pair(r,&rp2)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+ p->q1.am->base=p->q1.reg=r;
+ }else if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q1.reg==p->z.reg){
+ r=get_reg(f,p,POINTER);
+ cmp_get_acc(f,p,0);
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ if(!reg_pair(r,&rp2)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+ p->q1.reg=r;
+ }
+ if(p->q2.am&&p->q2.am->base==p->z.reg){
+ if(r==0){
+ r=get_reg(f,p,POINTER);
+ cmp_get_acc(f,p,0);
+ if(!reg_pair(p->q2.am->base,&rp)) ierror(0);
+ if(!reg_pair(r,&rp2)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+ }
+ p->q2.am->base=p->q2.reg=r;
+ }else if((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg==p->z.reg){
+ if(r==0){
+ r=get_reg(f,p,POINTER);
+ cmp_get_acc(f,p,0);
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ if(!reg_pair(r,&rp2)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+ }
+ p->q2.reg=r;
+ }
+ }
+ if(isacc(z)){
+ if(isacc(q2)){
+ if(p->q2.reg==rax){
+ r=get_reg(f,p,INT);
+ if(!reg_pair(r,&rp)) ierror(0);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tstx\t%s\n",mregnames[rp.r2]);
+ }else{
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ }
+ p->q2.reg=r;
+ if(isacc(q1))
+ p->q1.reg=r;
+ }
+ }
+ }
+
+ reload_acc(f);
+
+ regs[ra]=mra;
+ regs[rax]=mrax;
+}
+
+
+/* compare if two objects are the same */
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+ if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
+ return 1;
+ if(o1->flags==o2->flags&&o1->am==o2->am){
+ if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+ if(!(o1->flags®)||o1->reg==o2->reg){
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+ ierror(0);
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+ if(p->am){
+ if(p->am->flags==IMM_IND)
+ emit(f,"(%s),y ;am(%ld)",mregnames[p->am->base],p->am->offset);
+ else if(p->am->flags==GPR_IND)
+ emit(f,"(%s),y ;am(%s)",mregnames[p->am->base],mregnames[p->am->idx]);
+ else if(p->am->flags==ABS_IND){
+ emit(f,"%ld",p->am->offset);
+ if(p->am->v){
+ Var *v=p->am->v;
+ if(v->storage_class==EXTERN)
+ emit(f,"+%s%s",idprefix,v->identifier);
+ else
+ emit(f,"+%s%ld",labprefix,zm2l(v->offset));
+ }
+ if(ISIDX(p->am->idx))
+ emit(f,",%s ;am(%s)",mregnames[p->am->idx],mregnames[p->am->idx]);
+ else
+ emit(f,",y ;am(%s)",mregnames[p->am->idx]);
+ }else
+ ierror(0);
+ return;
+ }
+ if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if(p->flags&DREFOBJ) emit(f,"(");
+ if(p->flags®){
+ emit(f,"%s",mregnames[p->reg]);
+ }else if(p->flags&VAR) {
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+ emit(f,"(%s),y",mregnames[fp]);
+ else{
+ if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,MAXINT);emit(f,"+");}
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ }
+ }
+ if(p->flags&KONST){
+ if(/*ieee&&((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)*/ISFLOAT(t))
+ emit(f,"%s%d",labprefix,addfpconst(p,t));
+ else
+ emitval(f,&p->val,t&NU);
+ }
+ if(p->flags&DREFOBJ) emit(f,")%s",noy?"":",y");
+}
+
+/* Test if there is a sequence of FREEREGs containing FREEREG reg.
+ Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+ while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+ if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+ p=p->next;
+ }
+ return 0;
+}
+
+char amode_buff[8192];
+char *render_amode(struct AddressingMode *am)
+{
+ return "(amode: not implemented)";
+}
+
+char val_buff[8192];
+char *render_val(union atyps val)
+{
+ snprintf(val_buff,8192,"(val: %02x...)",
+ val.vuchar);
+ return val_buff;
+}
+
+char var_buff[8192];
+char *render_var(struct Var *v)
+{
+ if (!v) return "<null>";
+ snprintf(var_buff,8192,"(var id=%s)",v->identifier);
+ return var_buff;
+}
+
+char obj_buff[8192];
+char *render_obj(struct obj o)
+{
+ // XXX Calling render_var() can result in segfaults
+ snprintf(obj_buff,8192,"(flags=%d, reg=%d, dtype=%d, var=%s, amode=%s, val=%s)",
+ o.flags,o.reg,o.dtyp,"render_var(o.v)",render_amode(o.am),render_val(o.val));
+ return obj_buff;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+ int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+ fprintf(stderr,"peephole() called.\n");
+
+ /*
+ XXX PGS Things to consider adding here:
+ 1. Removal of dead loads when we know a register already has loaded the target we want.
+ 2. Removal of dead stores to local stack variables that never get read before returning from a function?
+ 3. Removal of SP decrement and increment, when no use of local stack is made.
+ 4. Promoting stack variables to global variables where it saves time and/or space?
+ 5. Using Z as a temporary scratch register for local variables, where it doesn't upset
+ other things?
+ */
+
+
+ for(;p;p=p->next){
+ fprintf(stderr," Instruction @ %p : ",p);
+ fprintf(stderr,"code=%d, ",p->code);
+ fprintf(stderr,"\n q1=%s, ",render_obj(p->q1));
+ fprintf(stderr,"\n q2=%s, ",render_obj(p->q2));
+ fprintf(stderr,"\n z=%s, ",render_obj(p->z));
+ fprintf(stderr,"\n");
+
+ c=p->code;
+ if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+ if(c==LABEL) exit_label=p->typf;
+
+ /* Try const(reg) */
+ if((c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&!ISFPOINTER(p->typf2)){
+ int base;zmax of;struct obj *o;
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ if(zmleq(Z0,of)&&zmleq(of,l2zm(255L))){
+ r=p->z.reg;
+ if(isreg(q1)&&isptr(p->q1.reg)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ int t,mc;
+ if((c2==ASSIGN|c2==PUSH)&&(p2->typf&NQ)==CHAR&&!zmeqto(p2->q2.val.vmax,Z1))
+ mc=1;
+ else
+ mc=0;
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||mc) break;
+ t=q1typ(p2)&NQ;
+ if(t>POINTER||ISFLOAT(t)) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||mc) break;
+ t=q2typ(p2)&NQ;
+ if(t>POINTER||ISFLOAT(t)) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||mc) break;
+ t=ztyp(p2)&NQ;
+ if(t>POINTER||ISFLOAT(t)) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else{
+ m=p2->z.reg;
+ if(o==&p->q1||o==&p->q2) break;
+ }
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ am->base=base;
+ am->offset=(int)zm2l(of);
+ if(isreg(q1)&&isptr(p->q1.reg)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+ /* Try reg,reg */
+ if(c==ADDI2P&&(p->typf&NU)==(UNSIGNED|CHAR)&&!ISFPOINTER(p->typf2)&&isreg(q2)&&p->q2.reg!=ra&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+ int base,idx,ind;struct obj *o;
+ r=p->z.reg;idx=p->q2.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ if((p->q1.flags&VARADR)||(p->q1.flags&(KONST|DREFOBJ))==KONST)
+ ind=0;
+ else
+ ind=1;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||(ind&&(q1typ(p2)&NQ)!=CHAR)) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||(ind&&(q2typ(p2)&NQ)!=CHAR)) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||(ind&&(ztyp(p2)&NQ)!=CHAR)) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->idx=idx;
+ if(ind){
+ am->flags=GPR_IND;
+ am->base=base;
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }else{
+ am->flags=ABS_IND;
+ am->base=0;
+ eval_const(&p->q1.val,MAXINT);
+ am->offset=zm2l(vmax);
+ if(p->q1.flags&VARADR)
+ am->v=p->q1.v;
+ else
+ am->v=0;
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+}
+
+static void pr(FILE *f,struct IC *p)
+{
+ int r;
+
+ if(zstoreflag){
+ int off;
+ if(p->z.flags!=VAR||p->z.v!=&bankv) ierror(0);
+ off=(int)zm2l(p->z.val.vmax);
+ p->z=zstore;
+ get_acc(f,p,INT);
+ if(zstore.flags&DREFOBJ){
+ if(!ISFPOINTER(zstore.dtyp)) ierror(0);
+ zstore.flags&=~DREFOBJ;
+ load_reg(f,LAST_PAIR,&zstore,POINTER);
+ if(indirect(&zstore)){
+ do_byte3(f,"lda",&zstore,FPOINTER);
+ emit(f,"\ttay\n");
+ }else
+ do_byte3(f,"ldy",&zstore,FPOINTER);
+ yval=NOVAL;
+ }else{
+ load_address(f,LAST_PAIR,&zstore,p->typf);
+ r=bank(zstore.v);
+ sety(f,r>=0?r:bankcnum);
+ }
+ emit(f,"\tldx\t#%d\n",off);
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ emit(f,"\tjsr\t%s__bankstore%d\n",idprefix,(int)zm2l(sizetab[p->typf&NQ]));
+ yval=NOVAL;
+ zstoreflag=0;
+ }
+
+ for(r=1;r<=MAXR;r++){
+ if(regs[r]&8)
+ regs[r]&=~8;
+ }
+ for(r=FIRST_GPR;r<=LAST_GPR;r++){
+ int ta=0;
+ if(regs[r]&2){
+ if(regs[ra]&&!pushedacc){
+ emit(f,"\ttay\n");
+ yval=NOVAL;
+ ta=1;
+ }
+ emit(f,"\tpla\n");
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ regs[r]&=~2;
+ }
+ if(ta)
+ emit(f,"\ttya\n");
+ }
+ if(pushedx){
+ emit(f,"\tldx\t%s\n",mregnames[pushedx]);
+ pushedx=0;
+ }
+
+ reload_acc_opt(f,p->next);
+}
+
+struct cmplist {struct cmplist *next;int from,to,mode;} *first_cmplist;
+
+static void add_cmplist(int from, int to, int mode)
+{
+ struct cmplist *new;
+ new=mymalloc(sizeof(*new));
+ new->next=first_cmplist;
+ new->from=from;
+ new->to=to;
+ new->mode=mode;
+ first_cmplist=new;
+}
+
+static void incsp(FILE *f,long of)
+{
+ if(of==0) return;
+ if(of==1||of==-1){
+ static obj o;
+ o.flags=REG;
+ o.reg=sp;
+ if(of==1)
+ incmem(f,&o,INT,ADD,1);
+ else
+ incmem(f,&o,INT,SUB,1);
+ }else if(of==256){
+ emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+ }else if(of==-256){
+ emit(f,"\tdec\t%s+1\n",mregnames[sp]);
+ }else{
+ long abs;
+ if(of>0){
+ abs=of;
+ emit(f,"\tclc\n");
+ }else{
+ abs=-of;
+ emit(f,"\tsec\n");
+ }
+ if(abs&255){
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ if(of>0){
+ emit(f,"\tadc\t#%ld\n",abs&255);
+ }else{
+ emit(f,"\tsbc\t#%ld\n",abs&255);
+ }
+ emit(f,"\tsta\t%s\n",mregnames[sp]);
+ }
+ if((abs&0xff00)==0){
+ if(of>0){
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+ emit(f,"%s%d:\n",labprefix,label);
+ }else{
+ emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+ emit(f,"\tdec\t%s+1\n",mregnames[sp]);
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }else{
+ emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+ if(of>0)
+ emit(f,"\tadc\t#%ld\n",(abs>>8)&255);
+ else
+ emit(f,"\tsbc\t#%ld\n",(abs>>8)&255);
+ emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+ }
+ }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+ int i,r,of;
+ rsavesize=0;
+ libsave=1;
+
+ if(!optsize||(v->tattr&NOCOMPRESS)) emit(f,";vcprmin=10000\n");
+ if(vlas) emit(f,"___fo\tset\t%ld\n",(long)argsize);
+ r=0;
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&®scratch[i]&&!regsa[i])){
+ if(i!=LAST_GPR-VOL_GPRS+1&&r==0) libsave=0;
+ rsavesize++;
+ r=1;
+ }else{
+ if(i==LAST_GPR-VOL_GPRS+1) libsave=0;
+ r=0;
+ }
+ }
+ rscnt=rsavesize;
+ if(rscnt&&!SOFTSTACK){
+ if(optspeed||rscnt<2)
+ rsavesize=0;
+ else if(!optsize&&rscnt<=5)
+ rsavesize=0;
+ }
+
+ if(!special_section(f,v)){emit(f,codename);ebank(f,bank(v));if(f) section=CODE;}
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\tglobal\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+
+ offset=localsize+argsize+rsavesize;
+
+ if(in_isr){
+ emit(f,"\tpha\n");
+ emit(f,"\tphx\n");
+ emit(f,"\tphy\n");
+ emit(f,"\tphz\n");
+ if(offset||function_calls){
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ emit(f,"\tpha\n");
+ emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+ emit(f,"\tpha\n");
+ emit(f,"\tlda\t#<(___isrstack-%ld)\n",offset);
+ emit(f,"\tsta\t%s\n",mregnames[sp]);
+ emit(f,"\tlda\t#>(___isrstack-%ld)\n",offset);
+ emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+ }
+ }
+
+ if(MAINARGS&&v->storage_class==EXTERN&&!strcmp(v->identifier,"main")&&v->vtyp->exact->count>1)
+ emit(f,"\tjsr\tinitmainargs\n");
+
+ yval=NOVAL;
+ of=argsize+localsize;
+
+ if(rsavesize>0&&of+rsavesize>255){
+ offset-=rsavesize;
+ incsp(f,-rsavesize);
+ of=0;
+ }else{
+ incsp(f,-offset);
+ offset=0;
+ }
+
+
+ if(!libsave||rscnt!=rsavesize||optspeed||rscnt<=1||(rscnt<=3&&(!optsize)))
+ libsave=0;
+
+ if(libsave){
+ sety(f,of+rsavesize-1);
+ emit(f,"\tjsr\t%s__rsave%ld\n",idprefix,rscnt);
+ yval=of;
+ }else{
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&®scratch[i]&&!regsa[i])){
+ if(rscnt!=rsavesize){
+ emit(f,"\tlda\t%s\n",mregnames[i]);
+ emit(f,"\tpha\n");
+ }else{
+ sety(f,of++);
+ emit(f,"\tlda\t%s\n",mregnames[i]);
+ emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+ }
+ }
+ }
+ }
+
+
+
+ incsp(f,-offset);
+
+ if(vlas){
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ emit(f,"\tsta\t%s\n",mregnames[fp]);
+ emit(f,"\tlda\t%s\n",mregnames[sp2]);
+ emit(f,"\tsta\t%s\n",mregnames[fp2]);
+ }
+}
+
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+ int i,of,ar;
+ struct cmplist *p;
+ offset=localsize+argsize+rsavesize;
+ of=argsize+localsize;
+
+ i=freturn(v->vtyp->next);
+ if(i==ra||i==rax) ar=1; else ar=0;
+
+ if(rscnt!=rsavesize){
+ if(ar&&!pushedacc){
+ pushedacc=t4;
+ emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+ }
+ for(i=LAST_GPR;i>=FIRST_GPR;i--){
+ if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&®scratch[i]&&!regsa[i])){
+ emit(f,"\tpla\n");
+ emit(f,"\tsta\t%s\n",mregnames[i]);
+ }
+ }
+ }
+ if(rsavesize>0&&of+rsavesize>255){
+ if(of!=1&&ar&&!pushedacc){
+ pushedacc=t4;
+ emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+ }
+ incsp(f,of);
+ offset-=of;
+ of=0;
+ }
+ if(rsavesize>0){
+ if(ar&&!pushedacc){
+ pushedacc=t4;
+ emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+ }
+ }
+ if(rsavesize){
+ if(libsave){
+ sety(f,of+rsavesize-1);
+ emit(f,"\tjsr\t%s__rload%ld\n",idprefix,rscnt);
+ yval=of;
+ }else{
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&®scratch[i]&&!regsa[i])){
+ sety(f,of++);
+ emit(f,"\tlda\t(%s),y\n",mregnames[sp]);
+ emit(f,"\tsta\t%s\n",mregnames[i]);
+ }
+ }
+ }
+ }
+ if(in_isr){
+ if(offset||function_calls){
+ emit(f,"\tpla\n");
+ emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+ emit(f,"\tpla\n");
+ emit(f,"\tsta\t%s\n",mregnames[sp]);
+ }
+ }else if(offset==2&&!pushedacc){
+ emit(f,"\tinc\t%s\n",mregnames[sp]);
+ emit(f,"\tbeq\t%s%d\n",labprefix,++label);
+ emit(f,"\tinc\t%s\n",mregnames[sp]);
+ emit(f,"\tbeq\t%s%d\n",labprefix,++label);
+ reload_acc(f);
+ emit(f,ret);
+ emit(f,"%s%d:\n",labprefix,label-1);
+ emit(f,"\tinc\t%s\n",mregnames[sp]);
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+ }else{
+ if(offset!=0&&ar&&!pushedacc){
+ pushedacc=t4;
+ emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+ }
+ incsp(f,offset);
+ }
+
+ reload_acc(f);
+
+ if(in_isr){
+ emit(f,"\tplz\n");
+ emit(f,"\tply\n");
+ emit(f,"\tplx\n");
+ emit(f,"\tpla\n");
+ }
+ emit(f,ret);
+
+ for(p=first_cmplist;p;){
+ struct cmplist *m;
+ emit(f,"%s%d:\n",labprefix,p->from);
+ if(p->mode==JMPIND){
+ /* indirect call */
+ emit(f,"\tjmp\t(%s)\n",mregnames[p->to]);
+ }else{
+ pushedacc=p->mode;
+ reload_acc(f);
+ emit(f,"\t%s\t%s%d\n",jmpinst,labprefix,p->to);
+ }
+ m=p;
+ p=p->next;
+ free(m);
+ }
+ first_cmplist=0;
+ pushedacc=0;
+}
+
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+int init_cg(void)
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(1L);
+ char_bit=l2zm(8L);
+ stackalign=l2zm(1);
+
+ if(IEEE){
+ ieee=1;
+ msizetab[DOUBLE]=msizetab[LDOUBLE]=l2zm(8L);
+ }
+
+
+ mregnames[0]=regnames[0]="noreg";
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"r%d",i-FIRST_GPR);
+ mregnames[i]=regnames[i];
+ regsize[i]=l2zm(1L);
+ regtype[i]=&ctyp;
+ }
+ for(i=FIRST_PAIR;i<=LAST_PAIR;i++){
+ int sr=(i-FIRST_PAIR)*2+FIRST_GPR;
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"%s/%s",mregnames[sr],mregnames[sr+1]);
+ mregnames[i]=regnames[sr];
+ regsize[i]=l2zm(2L);
+ regtype[i]=&ityp;
+ }
+ for(i=FIRST_BIG;i<=LAST_BIG;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"btmp%d",i-FIRST_BIG);
+ mregnames[i]=regnames[i];
+ regsize[i]=msizetab[FLOAT];
+ regtype[i]=&ftyp;
+ regsa[i]=0;
+ regscratch[i]=1;
+ }
+ for(i=FIRST_BIGP;i<=LAST_BIGP;i++){
+ int sr=(i-FIRST_BIGP)*2+FIRST_BIG;
+ regnames[i]=mymalloc(20);
+ sprintf(regnames[i],"%s/%s",mregnames[sr],mregnames[sr+1]);
+ mregnames[i]=regnames[sr];
+ regsize[i]=msizetab[LLONG];
+ regtype[i]=&lltyp;
+ regsa[i]=0;
+ regscratch[i]=1;
+ }
+
+ mregnames[ra] = regnames[ra] = "a";
+ mregnames[rx] = regnames[rx] = "x";
+ mregnames[ry] = regnames[ry] = "y";
+ mregnames[rz] = regnames[rz] = "z";
+ regsize[ra]=regsize[rx]=regsize[ry]=regsize[rz]=l2zm(1L);
+ regtype[ra]=regtype[rx]=regtype[ry]=regtype[rz]=&ctyp;
+ mregnames[sp]=regnames[sp] = "sp";
+ mregnames[sp1]=regnames[sp1] = "sp";
+ mregnames[sp2]=regnames[sp2] = "sp+1";
+
+ mregnames[rax]=regnames[rax] = "ax";
+ regsize[rax]=regsize[sp]=l2zm(2L);
+ regtype[rax]=regtype[sp]=&ityp;
+
+ reg_prio[ra]=reg_prio[rax]=100;
+ reg_prio[rx]=50;
+ reg_prio[rz]=50;
+
+ mregnames[raxyz]=regnames[raxyz] = "axyz";
+ regsize[raxyz]=l2zm(4L);
+ regtype[raxyz]=&ftyp;
+
+ /* Use multiple ccs. */
+ multiple_ccs=0;
+
+ short_push=1;
+
+ static_cse=0;
+
+ dref_cse=1;
+
+ /*prefer_statics=1; TODO */
+
+
+ if(optsize){
+ clist_copy_stack=2;
+ clist_copy_pointer=2;
+ clist_copy_static=2;
+ }else if(optspeed){
+ clist_copy_stack=64;
+ clist_copy_pointer=64;
+ clist_copy_static=64;
+ }else{
+ clist_copy_stack=8;
+ clist_copy_pointer=8;
+ clist_copy_static=8;
+ }
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[INT]=t_min(SHORT);
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[LONG]=ul2zum(2147483647UL);
+ t_max[INT]=t_max(SHORT);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[LONG]=ul2zum(4294967295UL);
+ tu_max[INT]=t_max(UNSIGNED|SHORT);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ /* This is not optimal but simple. */
+ regsa[raxyz]=regsa[ry]=regsa[sp]=regsa[sp1]=regsa[sp2]=REGSA_NEVER;
+ regsa[t1]=regsa[t2]=regsa[t3]=regsa[t4]=REGSA_NEVER;
+ regscratch[ra]=regscratch[rx]=regscratch[rax]=1;
+ if(!GLOBACC)
+ regsa[ra]=/*regsa[rx]=*/regsa[rax]=REGSA_TEMPS;
+ regscratch[sp]=regscratch[sp1]=regscratch[sp2]=regscratch[ry]=regscratch[rz]=0;
+ regscratch[t1]=regscratch[t2]=regscratch[t3]=regscratch[t4]=1;
+
+ for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++){
+ regscratch[i]=1;
+ if(i&1)
+ regscratch[FIRST_PAIR+(i-FIRST_GPR)/2]=1;
+ }
+
+ target_macros=marray;
+
+ declare_builtin("__mulint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__muluint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__divuint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__divint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__moduint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__modint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+
+ declare_builtin("__mulint32",LONG,LONG,FIRST_BIG+1,LONG,FIRST_BIG+2,1,0);
+ declare_builtin("__muluint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG+1,UNSIGNED|LONG,FIRST_BIG+2,1,0);
+ declare_builtin("__divint32",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+ declare_builtin("__divuint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+ declare_builtin("__modint32",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+ declare_builtin("__moduint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+
+ declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+ declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+ declare_builtin("__divint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__modint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__lsrint64",LLONG,LLONG,0,INT,0,1,0);
+ declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+ declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+
+ declare_builtin("__sint32toflt32",FLOAT,LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__uint32toflt32",FLOAT,UNSIGNED|LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__flt32tosint32",LONG,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__flt32touint32",UNSIGNED|LONG,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__sint16toflt32",FLOAT,INT,FIRST_PAIR,0,0,1,0);
+ declare_builtin("__uint16toflt32",FLOAT,UNSIGNED|INT,FIRST_PAIR,0,0,1,0);
+ declare_builtin("__flt32tosint16",INT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__flt32touint16",UNSIGNED|INT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+
+ declare_builtin("__sint32toflt64",DOUBLE,LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__uint32toflt64",DOUBLE,UNSIGNED|LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__flt64tosint32",LONG,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+ declare_builtin("__flt64touint32",UNSIGNED|LONG,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+ declare_builtin("__sint16toflt64",DOUBLE,INT,FIRST_PAIR,0,0,1,0);
+ declare_builtin("__uint16toflt64",DOUBLE,UNSIGNED|INT,FIRST_PAIR,0,0,1,0);
+ declare_builtin("__flt64tosint16",INT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+ declare_builtin("__flt64touint16",UNSIGNED|INT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+
+ declare_builtin("__flt64toflt32",FLOAT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+ declare_builtin("__flt32toflt64",DOUBLE,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+
+ declare_builtin("__addflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+ declare_builtin("__subflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+ declare_builtin("__mulflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+ declare_builtin("__divflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+ declare_builtin("__negflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__cmpsflt32",CHAR,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+
+#if 0
+ for(i=1;i<MAXR;i++){
+ printf("%02d %s scratch=%d ",i,regnames[i],regscratch[i]);
+ if(reg_pair(i,&rp))
+ printf("pair(%s,%s)",regnames[rp.r1],regnames[rp.r2]);
+ printf("\n");
+ }
+#endif
+
+ if(NOPEEP) nopeep=1;
+ if(CBMASCII) cbmascii=1;
+ if(ATASCII) atascii=1;
+ if(C02){
+ c02=1;
+ has_zero_reg=1;
+ has_inc_a=1;
+ jmpinst="bra";
+ }else
+ jmpinst="jmp";
+
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+
+ bankv.storage_class=EXTERN;
+ bankv.identifier="__bankv";
+ bankv.vtyp=new_typ();
+ bankv.vtyp->flags=CHAR;
+
+ bankcnum=COMMONBANK;
+
+ return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+/* A pointer MUST be returned in a register. The code-generator */
+/* has to simulate a pseudo register if necessary. */
+{
+ int typ=t->flags&NQ;
+ if(ISSTRUCT(typ)||ISUNION(typ)||typ==VOID)
+ return 0;
+ if(OLDFP&&ISFLOAT(typ)) return FIRST_GPR;
+ if(typ==LONG||typ==FLOAT||ISFPOINTER(typ)||(!ieee&&(typ==DOUBLE||typ==LDOUBLE)))
+ return FIRST_BIG;
+ if(typ==LLONG||(ieee&&(typ==DOUBLE||typ==LDOUBLE)))
+ return FIRST_BIGP;
+ if(zmleq(szof(t),l2zm(1L)))
+ return ra;
+ if(zmleq(szof(t),l2zm(2L)))
+ return rax;
+ else
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ if(r>=FIRST_PAIR&&r<=LAST_PAIR){
+ p->r1=(r-FIRST_PAIR)*2+FIRST_GPR;
+ p->r2=p->r1+1;
+ return 1;
+ }else if(r>=FIRST_BIGP&&r<=LAST_BIGP){
+ p->r1=(r-FIRST_BIGP)*2+FIRST_BIG;
+ p->r2=p->r1+1;
+ return 1;
+ }else if(r==rax){
+ p->r1=ra;
+ p->r2=rx;
+ return 1;
+ }else if(r==raxyz) {
+ // TODO: PGS: How do we declare a reg pair that is made of 4 regs, not 2?
+ return 0;
+ }else if(r==sp){
+ p->r1=sp1;
+ p->r2=sp2;
+ return 1;
+ }
+ return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+ register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+ int c=p->code;
+ if(ISIDX(r)){
+ if(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP){
+ if(o==&p->q2&&c!=ADDI2P) return -2;
+ }else if(c==ASSIGN){
+ if(o==&p->q1&&indirect(&p->z)) return 1;
+ if(o==&p->z&&indirect(&p->q1)) return 1;
+ }else if(c==COMPARE){
+ //if(o==&p->q1&&indirect(&p->q2)) return INT_MIN;
+ //if(o==&p->q2&&indirect(&p->q1)) return INT_MIN;
+ }else if(c==TEST){
+ }else if(c==SETRETURN||c==GETRETURN){
+ }else
+ return INT_MIN;
+ }
+ /*TODO: adapt this */
+ if(o->flags&VKONST){
+ return 0;
+ if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
+ return 4;
+ else
+ return 2;
+ }
+ if(o->flags&DREFOBJ){
+ if(isptr(r))
+ return 4;
+ if(r==rax)
+ return INT_MIN;
+ }
+ if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 6;
+ if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 6;
+ if(r==ra)
+ return 5;
+ if(ISIDX(r))
+ return 4;
+ if(r==rax)
+ return 2;
+ return 2;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(r==0)
+ return 0;
+ if(r==rax&&NORAX)
+ return 0;
+ t&=NQ;
+ if(ISCHAR(t))
+ if(r==ra||(ISIDX(r)&&(optflags&2))||(r>=FIRST_GPR&&r<=LAST_GPR))
+ return 1;
+ if(ISSHORT(t)){
+ if(r==rax){
+ if(t==POINTER&&mode<0)
+ return 1;
+ if(t!=POINTER)
+ return 1;
+ }
+ if(r>=FIRST_PAIR&&r<=LAST_PAIR)
+ return 1;
+ }
+ if(r>=FIRST_BIG&&r<=LAST_BIG){
+ if(t==LONG||t==FLOAT||((t==DOUBLE||t==LDOUBLE)&&!ieee))
+ return 1;
+ if(t==FPOINTER)
+ return 1;
+ }
+ if(r>=FIRST_BIGP&&r<=LAST_BIGP){
+ if(t==LLONG||((t==DOUBLE||t==LDOUBLE)&&ieee))
+ return 1;
+ }
+ return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* On the PowerPC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op=o&NQ,tp=t&NQ;
+
+ if(op==tp) return 0;
+ if(ISCHAR(op)&&ISCHAR(tp)) return 0;
+ if(ISSHORT(op)&&ISSHORT(tp)) return 0;
+ if(!ieee&&ISFLOAT(op)&&ISFLOAT(tp)) return 0;
+ if(op==DOUBLE&&tp==LDOUBLE) return 0;
+ if(op==LDOUBLE&&tp==DOUBLE) return 0;
+
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ if(STDSYNTAX)
+ emit(f,"\tspace\t%ld\n",zm2l(size));
+ else
+ emit(f,"\treserve\t%ld\n",zm2l(size));
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ if(zm2l(align)>1) emit(f,"\talign 1\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag,b=bank(v);char *sec;
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(v->tattr&ZPAGE)
+ emit(f,"\tzpage\t%s%ld\n",labprefix,zm2l(v->offset));
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))){emit(f,dataname);ebank(f,b);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)){emit(f,rodataname);ebank(f,b);if(f) section=RODATA;}
+ if(!v->clist){emit(f,bssname);ebank(f,b);if(f) section=BSS;}
+ }
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ newobj=1;
+ }
+ if(v->storage_class==EXTERN){
+ emit(f,"\tglobal\t%s%s\n",idprefix,v->identifier);
+ if(v->tattr&ZPAGE)
+ emit(f,"\tzpage\t%s%s\n",idprefix,v->identifier);
+ if(v->flags&(DEFINED|TENTATIVE)){
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))){emit(f,dataname);ebank(f,b);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)){emit(f,rodataname);ebank(f,b);if(f) section=RODATA;}
+ if(!v->clist){emit(f,bssname);ebank(f,b);if(f) section=BSS;}
+ }
+
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ if(ISCHAR(t))
+ emit(f,"\tbyte\t");
+ else
+ emit(f,"\tword\t");
+ if(!p->tree){
+ if(ISLONG(t)||ISFLOAT(t)){
+ if(ieee&&ISFLOAT(t)){
+ emit_ieee(f,&p->val,t&NQ);
+ }else{
+ eval_const(&p->val,t&NU);
+ if(ISFLOAT(t)) cnv_fp();
+ gval.vmax=zmand(vmax,l2zm(0xffffL));
+ emitval(f,&gval,MAXINT);
+ emit(f,",");
+ gval.vmax=zmand(zmrshift(vmax,l2zm(16L)),l2zm(0xffffL));
+ emitval(f,&gval,MAXINT);
+ }
+ }else{
+ if(ISFPOINTER(t)){
+ eval_const(&p->val,t&NU);
+ emit(f,"%ld\n",(long)zm2l(vmax)&0xffff);
+ emit(f,"\tbyte\t%d\n",(int)((zm2l(vmax)>>16)&0xff));
+ }else
+ emitval(f,&p->val,t&NU);
+ }
+ }else{
+ emit_obj(f,&p->tree->o,t&NU);
+ if(ISFPOINTER(t)){
+ int b;
+ if((p->tree->o.flags&(VAR|VARADR))!=(VAR|VARADR)) ierror(0);
+ b=bank(p->tree->o.v);
+ emit(f,"\n\tbyte\t%d",b>=0?b:bankcnum);
+ }
+ }
+ emit(f,"\n");newobj=0;
+}
+
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/* The main code-generation. */
+{
+ int c,t,i;
+ struct IC *mi;
+ FILE *rf=f;
+ static char *dbgfile;
+ static int dbgline;
+
+ if(vlas){
+ fp=FPVLA_REG;
+ if(!reg_pair(fp,&rp)) ierror(0);
+ fp1=rp.r1;
+ fp2=rp.r2;
+ regused[fp]=regused[fp1]=regused[fp2]=1;
+ }else{
+ fp=sp;
+ fp1=sp1;
+ fp2=sp2;
+ }
+ argsize=0;
+ localsize=offset;
+ if(DEBUG&1) printf("gen_code()\n");
+
+ cbank=bank(v);
+
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_REGS;
+
+ for(pass=0;pass<2;pass++){
+
+ if(DEBUG&1) printf("pass %d\n",pass);
+
+ if(pass==0){
+ f=0;
+ mi=clone_ic(p);
+ }else
+ f=rf;
+
+ for(c=1;c<=MAXR;c++) regs[c]=0; /*regsa[c];*/
+ maxpushed=0;
+
+ /*FIXME*/
+ if(v->tattr&INTERRUPT){
+ ret="\trti\n";
+ in_isr=1;
+ }else{
+ ret="\trts\n";
+ in_isr=0;
+ }
+
+ if(!nopeep) peephole(pass==0?p:mi);
+
+ function_top(f,v,localsize);
+
+ pushed=0;
+
+ yval=NOVAL;
+
+ dbgfile=0;
+ dbgline=0;
+
+ for(p=pass==0?p:mi;p;pr(f,p),p=p->next){
+
+
+
+ if(DEBUG&1) pric2(stdout,p);
+
+ if(debug_info){
+ if(p->file&&p->line){
+ if(p->file!=dbgfile||p->line!=dbgline){
+ dbgfile=p->file;
+ dbgline=p->line;
+ emit(f,"; %d \"%s\"\n",dbgline,dbgfile);
+ }
+ }
+ }
+
+ c=p->code;t=p->typf;
+
+ if(c==NOP) {p->z.flags=0;continue;}
+ if(c==ALLOCREG){
+ regs[p->q1.reg]=1;
+ if(reg_pair(p->q1.reg,&rp)){
+ regs[rp.r1]=1;
+ regs[rp.r2]=1;
+ }
+ continue;
+ }
+ if(c==FREEREG){
+ regs[p->q1.reg]=0;
+ if(reg_pair(p->q1.reg,&rp)){
+ regs[rp.r1]=0;
+ regs[rp.r2]=0;
+ }
+ continue;
+ }
+ if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);yval=NOVAL;continue;}
+ if(c==BRA){
+ yval=NOVAL;
+ if(t==exit_label&&localsize+argsize+rsavesize+rscnt==0)
+ emit(f,ret);
+ else
+ emit(f,"\t%s\t%s%d\n",jmpinst,labprefix,t);
+ continue;
+ }
+ if(c>=BEQ&&c<BRA){
+ yval=NOVAL;
+ continue;
+ }
+
+ if(c==MOVETOREG){
+ p->code=c=ASSIGN;
+ p->typf=t=regtype[p->z.reg]->flags;
+ p->q2.val.vmax=sizetab[regtype[p->z.reg]->flags];
+ }
+ if(c==MOVEFROMREG){
+ p->code=c=ASSIGN;
+ p->typf=t=regtype[p->q1.reg]->flags;
+ p->q2.val.vmax=sizetab[regtype[p->q1.reg]->flags];
+ }
+ if(c==CONVERT&&ISCHAR(t)&&ISCHAR(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[CHAR];
+ }
+ if(c==CONVERT&&msizetab[t&NQ]==3&&msizetab[p->typf2&NQ]==3){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[SHORT];
+ }
+ if(c==CONVERT&&ISSHORT(t)&&ISSHORT(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[SHORT];
+ }
+ if(c==CONVERT&&ISLONG(t)&&ISLONG(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[LONG];
+ }
+ if(c==CONVERT&&ISLLONG(t)&&ISLLONG(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[LLONG];
+ }
+ if(c==CONVERT&&ISFLOAT(t)&&ISFLOAT(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[t&NQ];
+ }
+
+
+ /* switch commutative operands if suitable */
+ if(c==ADD||c==MULT||c==AND||c==XOR||c==OR||(c==ADDI2P&&ISSHORT(t)&&!ISFPOINTER(p->typf2))){
+ if(compare_objects(&p->q2,&p->z)||isacc(q2)){
+ struct obj tmp;
+ tmp=p->q1;
+ p->q1=p->q2;
+ p->q2=tmp;
+ }
+ }
+
+ if(c==COMPARE&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+ obj tmp;
+ tmp=p->q1;
+ p->q1=p->q2;
+ p->q2=tmp;
+ }
+
+ c=p->code;
+ if(c==SUBPFP) c=SUB;
+ /*if(c==ADDI2P) c=ADD;*/
+ /*if(c==SUBIFP) c=SUB;*/
+
+
+ if(c==MINUS){
+ if(isacc(q1)&&isacc(z)){
+ if(ISCHAR(t)){
+ emit(f,"\tneg\n");
+ }else{
+ emit(f,"\teor\t#255\n");
+ emit(f,"\tclc\n");
+ emit(f,"\tadc\t#1\n");
+ }
+ if(!ISCHAR(t)){
+ emit(f,"\tpha\n");
+ emit(f,"\ttxa\n");
+ emit(f,"\teor\t#255\n");
+ emit(f,"\tadc\t#0\n");
+ emit(f,"\ttax\n");
+ emit(f,"\tpla\n");
+ }
+ continue;
+ }
+ p->code=c=SUB;
+ p->q2=p->q1;
+ p->q1.flags=KONST;
+ p->q1.am=0;
+ gval.vmax=Z0;
+ eval_const(&gval,MAXINT);
+ insert_const(&p->q1.val,t);
+ }
+
+ preload(f,p);
+
+ if(c==CONVERT){
+ int to=q1typ(p)&NU;
+ t&=NU;
+ if(ISCHAR(t)){
+ get_acc(f,p,CHAR);
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+ continue;
+ }
+ if(ISLONG(to)){
+ if(!isacc(z))
+ get_acc(f,p,CHAR);
+ if(zm2l(sizetab[t&NQ])==3){
+ do_byte3(f,"lda",&p->q1,to);
+ do_byte3(f,"sta",&p->z,t);
+ }
+ if(zm2l(sizetab[t&NQ])>=2){
+ load_hibyte(f,&p->q1,to);
+ store_hibyte(f,&p->z,t);
+ }
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+ continue;
+ }
+ if(ISSHORT(to)){
+ if((t&UNSIGNED)||ISFPOINTER(t))
+ get_acc(f,p,CHAR);
+ else
+ get_acc(f,p,SHORT);
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+ load_hibyte(f,&p->q1,to);
+ store_hibyte(f,&p->z,t);
+ if(ISFPOINTER(t)){
+ int b=-1;
+ if((p->q1.flags&(VARADR|DREFOBJ))==VARADR) b=bank(p->q1.v);
+ emit(f,"\tlda\t#%d\n",b>=0?b:bankcnum);
+ do_byte3(f,"sta",&p->z,t);
+ continue;
+ }
+ if(to&UNSIGNED){
+ if(has_zero_reg&&!indirect(&p->z)){
+ // 65C02 Z is Zero, not a changeable register, so we can
+ // use it to clear upper bytes.
+ // This is NOT the case on 4510/M65, where Z is an index register
+ do_byte3(f,"stz",&p->z,t);
+ do_byte4(f,"stz",&p->z,t);
+ }else{
+ emit(f,"\tlda\t#0\n");
+ do_byte3(f,"sta",&p->z,t);
+ do_byte4(f,"sta",&p->z,t);
+ }
+ }else{
+ emit(f,"\tldx\t#0\n");
+ emit(f,"\tcmp\t#0\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdex\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(indirect(&p->z)){
+ emit(f,"\ttxa\n");
+ do_byte3(f,"sta",&p->z,t);
+ do_byte4(f,"sta",&p->z,t);
+ }else{
+ do_byte3(f,"stx",&p->z,t);
+ do_byte4(f,"stx",&p->z,t);
+ }
+ }
+ continue;
+ }
+ if(ISCHAR(to)){
+ if(to&UNSIGNED){
+ get_acc(f,p,CHAR);
+ if(ISLONG(t)){
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+ if(has_zero_reg&&!indirect(&p->z)){
+ // 65C02 Z is Zero, not a changeable register, so we can
+ // use it to clear upper bytes.
+ // This is NOT the case on 4510/M65, where Z is an index register
+ do_hibyte(f,"stz",&p->z,t);
+ do_byte3(f,"stz",&p->z,t);
+ if(ISLONG(t))
+ do_byte4(f,"stz",&p->z,t);
+ }else{
+ emit(f,"\tlda\t#0\n");
+ store_hibyte(f,&p->z,t);
+ do_byte3(f,"sta",&p->z,t);
+ if(ISLONG(t))
+ do_byte4(f,"sta",&p->z,t);
+ }
+ continue;
+ }
+ if(isacc(z))
+ emit(f,"\tldx\t#0\n");
+ else if(isacc(q1)){
+ emit(f,"\tldx\t#0\n");
+ store_acc(f,&p->z,t);
+ continue;
+ }else{
+ if(has_zero_reg&&!indirect(&p->z)){
+ // 65C02 Z is Zero, not a changeable register, so we can
+ // use it to clear upper bytes.
+ // This is NOT the case on 4510/M65, where Z is an index register
+ do_hibyte(f,"stz",&p->z,t);
+ }else{
+ emit(f,"\tlda\t#0\n");
+ store_hibyte(f,&p->z,t);
+ }
+ }
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+ }else{
+ int l=++label;
+ get_acc(f,p,SHORT);
+ emit(f,"\tldx\t#0\n");
+ if(isreg(q1)&&p->q1.reg==ra)
+ emit(f,"\tcmp\t#0\n");
+ else
+ load_lobyte(f,&p->q1,to);
+ emit(f,"\tbpl\t%s%d\n",labprefix,label);
+ emit(f,"\tdex\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ store_lobyte(f,&p->z,t);
+ if(indirect(&p->z)&&(!isreg(z)||p->z.reg!=rax)){
+ emit(f,"\ttxa\n");
+ store_hibyte(f,&p->z,t);
+ if(ISLONG(t)){
+ do_byte3(f,"sta",&p->z,t);
+ do_byte4(f,"sta",&p->z,t);
+ }
+ }else{
+ if(!isreg(z)||p->z.reg!=rax){
+ emit(f,"\tstx\t");
+ emit_hibyte(f,&p->z,t);
+ emit(f,"\n");
+ }
+ if(ISLONG(t)){
+ do_byte3(f,"stx",&p->z,t);
+ do_byte4(f,"stx",&p->z,t);
+ }
+ }
+ }
+ if(ISFPOINTER(t)){
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ do_byte3(f,"sta",&p->z,t);
+ }
+ continue;
+ }
+ if(ISFPOINTER(to)){
+ get_acc(f,p,CHAR);
+ if(zm2l(sizetab[t&NQ])>=3){
+ do_byte3(f,"lda",&p->q1,to);
+ do_byte3(f,"sta",&p->z,t);
+ }
+ if(zm2l(sizetab[t&NQ])>=2){
+ load_hibyte(f,&p->q1,to);
+ store_hibyte(f,&p->z,t);
+ }
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+
+ continue;
+ }
+ ierror(0);
+ }
+
+ if(c==KOMPLEMENT){
+ get_acc(f,p,CHAR);
+ if(ISCHAR(t)){
+ load_acc(f,&p->q1,t);
+ emit(f,"\teor\t#-1\n");
+ store_acc(f,&p->z,t);
+ }else{
+ if(isacc(q1))
+ emit(f,"\tpha\n");
+ if(ISLONG(t)){
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\teor\t#-1\n");
+ do_byte4(f,"sta",&p->z,t);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\teor\t#-1\n");
+ do_byte3(f,"sta",&p->z,t);
+ }
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\teor\t#-1\n");
+ store_hibyte(f,&p->z,t);
+ if(isacc(q1))
+ emit(f,"\tpla\n");
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\teor\t#-1\n");
+ store_lobyte(f,&p->z,t);
+ }
+ continue;
+ }
+ if(c==SETRETURN){
+ t&=NQ;
+ if(isreg(q1)&&p->q1.reg==p->z.reg) continue;
+ if(t==LONG||t==LLONG||ISFLOAT(t)||ISFPOINTER(t)){
+ long l=zm2l(p->q2.val.vmax);
+ int zr=p->z.reg;
+ //get_acc(f,p,t);
+ if((optsize||l>4)&&!ISFPOINTER(t)){
+ int ind=indirect(&p->q1);
+ if(ind) load_address(f,LAST_PAIR,&p->q1,t);
+ BSET(regused,t3);
+ BSET(regused,t4);
+ sety(f,l-1);
+ emit(f,"%s%d:\n",labprefix,++label);
+ if(ind)
+ emit(f,"\tlda\t(%s),y\n",mregnames[LAST_PAIR]);
+ else{
+ emit(f,"\tlda\t");
+ if(!ISFLOAT(t)&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+ emit(f,"%s%d",labprefix,addfpconst(&p->q1,t));
+ }else
+ emit_obj(f,&p->q1,t);
+ emit(f,",y\n");
+ }
+ emit(f,"\tsta\t%s,y\n",mregnames[zr]);
+ emit(f,"\tdey\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,label);
+ yval=255;
+ }else{
+ if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ if(p->q1.reg==zr){
+ int r=get_reg(f,p,POINTER);
+ if(r==FIRST_PAIR||r==FIRST_PAIR+1)
+ ierror(0);
+ if(!reg_pair(r,&rp2)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[zr]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tlda\t%s+1\n",mregnames[zr]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+ p->q1.reg=r;
+ }
+ }
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[zr]);
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s+1\n",mregnames[zr]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s+2\n",mregnames[zr]);
+ if(!ISFPOINTER(t)){
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s+3\n",mregnames[zr]);
+ }
+ /*TODO:regused OLDFP */
+ regused[zr]=1;
+ }
+ continue;
+ }
+ //get_acc(f,p,t);
+ load_acc(f,&p->q1,t);
+ regused[ra]=1;
+ regused[rx]=1;
+ continue;
+ }
+ if(c==GETRETURN){
+ t&=NQ;
+ if(isreg(z)&&p->q1.reg==p->z.reg) continue;
+ if(t==LONG||t==LLONG||ISFLOAT(t)||ISFPOINTER(t)){
+ long l=zm2l(p->q2.val.vmax);
+ int qr=p->q1.reg;
+ if((optsize||l>4)&&!ISFPOINTER(t)){
+ int ind=indirect(&p->z);
+ if(ind) load_address(f,LAST_PAIR,&p->z,t);
+ BSET(regused,t3);
+ BSET(regused,t4);
+ sety(f,l-1);
+ emit(f,"%s%d:\n",labprefix,++label);
+ emit(f,"\tlda\t%s,y\n",mregnames[qr]);
+ if(ind)
+ emit(f,"\tsta\t(%s),y\n",mregnames[LAST_PAIR]);
+ else{
+ emit(f,"\tsta\t");
+ emit_obj(f,&p->z,t);
+ emit(f,",y\n");
+ }
+ emit(f,"\tdey\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,label);
+ yval=255;
+ }else{
+ if((p->z.reg&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ if(p->z.reg==qr) ierror(0);
+ }
+ emit(f,"\tlda\t%s\n",mregnames[qr]);
+ store_lobyte(f,&p->z,t);
+ emit(f,"\tlda\t%s+1\n",mregnames[qr]);
+ store_hibyte(f,&p->z,t);
+ emit(f,"\tlda\t%s+2\n",mregnames[qr]);
+ do_byte3(f,"sta",&p->z,t);
+ if(!ISFPOINTER(t)){
+ emit(f,"\tlda\t%s+3\n",mregnames[qr]);
+ do_byte4(f,"sta",&p->z,t);
+ }
+ }
+ continue;
+ }
+ if(p->q1.reg)
+ store_acc(f,&p->z,t);
+ continue;
+ }
+ if(c==CALL){
+ int reg;
+
+ if(argsize<zm2l(p->q2.val.vmax)) argsize=zm2l(p->q2.val.vmax);
+
+ /*FIXME*/
+#if 0
+ if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+ if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+ stack=framesize+zum2ul(p->q1.v->fi->stack1);
+ }else
+ stack_valid=0;
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+ long of=va_offset(v)+localsize+rsavesize+argsize;
+ emit(f,"\tlda\t%s\n",mregnames[fp]);
+ if(of){
+ emit(f,"\tclc\n");
+ if(of&255)
+ emit(f,"\tadc\t#%d\n",(of&255));
+ }
+ emit(f,"\tldx\t%s+1\n",mregnames[fp]);
+ if(of&0xff00){
+ emit(f,"\tpha\n");
+ emit(f,"\ttxa\n");
+ emit(f,"\tadc\t#%d\n",(of>>8)&255);
+ emit(f,"\ttax\n");
+ emit(f,"\tpla\n");
+ }else if(of){
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ emit(f,"\tinx\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ continue;
+ }
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit(f,";startinline\n");
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ emit(f,";endinline\n");
+ }else if(p->q1.flags&DREFOBJ){
+ if(ISFPOINTER(p->q1.dtyp)){
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,LAST_PAIR,&p->q1,POINTER);
+ if(indirect(&p->q1)){
+ do_byte3(f,"lda",&p->q1,FPOINTER);
+ emit(f,"\ttay\n");
+ }else
+ do_byte3(f,"ldy",&p->q1,FPOINTER);
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ emit(f,"\tjsr\t%s__bankjsr\n",idprefix);
+ yval=NOVAL;
+ }else{
+ if(!(p->q1.flags®)) ierror(0);
+ emit(f,"\tjsr\t%s%d\n",labprefix,++label);
+ yval=NOVAL;
+ add_cmplist(label,p->q1.reg,JMPIND);
+ }
+ }else{
+ int tbank=-1;
+ if(p->q1.flags&VAR) tbank=bank(p->q1.v);
+ if(tbank!=cbank&&tbank>=0){
+ if(cbank>=0){
+ load_address(f,LAST_PAIR,&p->q1,t);
+ sety(f,tbank);
+ emit(f,"\tlda\t#%d\n",cbank);
+ emit(f,"\tjsr\t%s__bankjsr\n",idprefix);
+ yval=NOVAL;
+ continue;
+ }
+ sety(f,tbank);
+ emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+ yval=NOVAL;
+ }
+ if((p->q1.flags&VAR)&&!strcmp(p->q1.v->identifier,"_fmemcpy"))
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ emit(f,"\tjsr\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ pushed-=zm2l(p->q2.val.vmax);
+ if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS;
+ yval=NOVAL;
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(t==0) ierror(0);
+ if((p->q1.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)==LLONG){
+ int i;
+ eval_const(&p->q1.val,t);
+ for(i=0;i<8;i++){
+ emit(f,"\tlda\t#%d\n",zm2l(vmax)&255);
+ vmax=zmrshift(vmax,l2zm(8L));
+ if(c==PUSH||(p->z.flags&DREFOBJ)){
+ sety(f,i+((c==PUSH)?pushed:0));
+ emit(f,"\tsta\t(%s),y\n",(c==PUSH)?mregnames[sp]:mregnames[p->z.reg]);
+ }else{
+ p->z.val.vmax=zmadd(p->z.val.vmax,l2zm((long)i));
+ emit(f,"\tsta\t");
+ emit_lobyte(f,&p->z,t);
+ emit(f,"\n");
+ p->z.val.vmax=zmsub(p->z.val.vmax,l2zm((long)i));
+ }
+ }
+ if(c==PUSH) pushed+=8;
+ continue;
+ }
+
+ if(!zmleq(p->q2.val.vmax,l2zm(4L))){
+ long len=zm2l(p->q2.val.vmax);
+ int r1,r2,loops,looplab;
+ if(len>32767) ierror(0);
+ if(!NOBANKVARS){
+ int bq=-1,bz=-1,s=-1;
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR) bq=bank(p->q1.v);
+ if((p->z.flags&(VAR|DREFOBJ))==VAR) bz=bank(p->z.v);
+ if(((p->q1.flags&DREFOBJ)&&ISFPOINTER(p->q1.dtyp))||
+ ((p->z.flags&DREFOBJ)&&ISFPOINTER(p->z.dtyp))){
+ far_copy(f,p);
+ continue;
+ }
+ if(cbank<0){
+ if(bq>=0&&bz>=0){
+ if(bq!=bz){
+ far_copy(f,p);
+ continue;
+ }
+ s=bq;
+ }else{
+ if(bq>=0) s=bq;
+ if(bz>=0) s=bz;
+ }
+ if(s>=0){
+ sety(f,s);
+ emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+ yval=NOVAL;
+ }
+ }else{
+ if((bq>=0&&bq!=cbank)||(bz>=0&&bz!=cbank)){
+ far_copy(f,p);
+ continue;
+ }
+ }
+ }
+ get_acc(f,p,CHAR);
+ if((p->q1.flags&(DREFOBJ|KONST))==DREFOBJ){
+ if(p->q1.flags®){
+ r1=p->q1.reg;
+ if(!reg_pair(r1,&rp)) ierror(0);
+ if(len>128){
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tclc\n");
+ if(len&128)
+ emit(f,"\tadc\t#128\n");
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ if(len>255){
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tadc\t#%ld\n",(len>>8)&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ }else{
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ emit(f,"\tinc\t%s\n",mregnames[rp.r2]);
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }
+ }else
+ ierror(0);
+ }else if(!indirect(&p->q1)&&len<=128&&(p->q1.flags&(DREFOBJ|KONST))!=KONST){
+ r1=0;
+ }else{
+ Var *v=p->q1.v;
+ /*if((p->q1.flags&(VARADR|VAR))!=VAR) ierror(0);*/
+ r1=get_reg(f,p,POINTER);
+ if(len>128) p->q1.val.vmax=zmadd(p->q1.val.vmax,l2zm(len&0xff80));
+ load_address(f,r1,&p->q1,t);
+ if(len>128) p->q1.val.vmax=zmsub(p->q1.val.vmax,l2zm(len&0xff80));
+ }
+ if((p->z.flags&(DREFOBJ|KONST))==DREFOBJ){
+ if(p->z.flags®){
+ r2=p->z.reg;
+ if(!reg_pair(r2,&rp)) ierror(0);
+ if(len>128){
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tclc\n");
+ if(len&128)
+ emit(f,"\tadc\t#128\n");
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ if(len>255){
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tadc\t#%ld\n",(len>>8)&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ }else{
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ emit(f,"\tinc\t%s\n",mregnames[rp.r2]);
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }
+ }else
+ ierror(0);
+ }else if(c==PUSH){
+ if(len<=128&&pushed==0){
+ r2=sp;
+ }else{
+ r2=get_reg(f,p,POINTER);
+ if(!reg_pair(r2,&rp)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ emit(f,"\tclc\n");
+ if(((pushed+(len&128))&255)!=0)
+ emit(f,"\tadc\t#%ld\n",(pushed+(len&128))&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[sp2]);
+ emit(f,"\tadc\t#%ld\n",((pushed+len)>>8)&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ }
+ }else if(!indirect(&p->z)&&len<=128){
+ r2=0;
+ }else{
+ Var *v=p->z.v;
+ r2=get_reg(f,p,POINTER);
+ if(len>128) p->z.val.vmax=zmadd(p->z.val.vmax,l2zm(len&0xff80));
+ load_address(f,r2,&p->z,t);
+ if(len>128) p->z.val.vmax=zmsub(p->z.val.vmax,l2zm(len&0xff80));
+ }
+ if(len>128){
+ get_acc(f,p,POINTER); /* get x */
+ emit(f,"\tldx\t#%ld\n",((len>>7)+1)&255);
+ }
+ sety(f,(len-1)&127);
+ if((optsize&&len>4)||len>8){
+ emit(f,"%s%d:\n",labprefix,looplab=++label);
+ if(optsize)
+ loops=1;
+ else{
+ if((len&3)==0)
+ loops=4;
+ else if((len&1)==0)
+ loops=2;
+ else
+ loops=1;
+ }
+ }else
+ loops=len;
+ if(r1&&!reg_pair(r1,&rp)) ierror(0);
+ if(r2&&!reg_pair(r2,&rp2)) ierror(0);
+ for(i=0;i<loops;i++){
+ if(r1)
+ emit(f,"\tlda\t(%s),y\n",mregnames[rp.r1]);
+ else{
+ emit(f,"\tlda\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,",y\n");
+ }
+ if(r2)
+ emit(f,"\tsta\t(%s),y\n",mregnames[rp2.r1]);
+ else{
+ emit(f,"\tsta\t");
+ emit_obj(f,&p->z,t);
+ emit(f,",y\n");
+ }
+ emit(f,"\tdey\n");
+ }
+ if(loops!=len){
+ emit(f,"\tbpl\t%s%d\n",labprefix,label);
+ }
+ if(len>128){
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tsec\n");
+ emit(f,"\tsbc\t#128\n");
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+ emit(f,"\tdec\t%s\n",mregnames[rp.r2]);
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tlda\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tsec\n");
+ emit(f,"\tsbc\t#128\n");
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+ emit(f,"\tdec\t%s\n",mregnames[rp2.r2]);
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tldy\t#127\n");
+ emit(f,"\tdex\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,looplab);
+ }
+ yval=NOVAL;
+ if(c==PUSH)
+ pushed+=zm2l(p->q2.val.vmax);
+ continue;
+ }
+ if(c==PUSH){
+ get_acc(f,p,CHAR);
+ load_lobyte(f,&p->q1,t);
+ if(c02&&pushed==0){
+ emit(f,"\tsta\t(%s)\n",mregnames[sp]);
+ }else{
+ sety(f,pushed);
+ emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+ }
+ if(!zmleq(p->q2.val.vmax,Z1)){
+ load_hibyte(f,&p->q1,t);
+ sety(f,pushed+1);
+ emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+ }
+ if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+ do_byte3(f,"lda",&p->q1,t);
+ sety(f,pushed+2);
+ emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+ }
+ if(!zmleq(p->q2.val.vmax,l2zm(3L))){
+ do_byte4(f,"lda",&p->q1,t);
+ sety(f,pushed+3);
+ emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+ }
+
+ pushed+=zm2l(p->q2.val.vmax);
+ continue;
+ }
+ if(c==ASSIGN){
+ int c2m;unsigned long v;
+ if(isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg) continue;
+ if(isacc(q1)){
+ if(p->q1.reg==rax) get_acc(f,p,CHAR);
+ store_acc(f,&p->z,t);
+ continue;
+ }
+ if(c02&&!indirect(&p->z)&&(p->q1.flags&(DREFOBJ|KONST))==KONST){
+ eval_const(&p->q1.val,t);
+ if(ISFLOAT(t)){
+ cnv_fp();
+ v=zum2ul(zm2zum(vmax));
+ }else
+ v=zum2ul(vumax);
+ c2m=1;
+ }else
+ c2m=0;
+ if(!c2m||v!=0)
+ get_acc(f,p,CHAR);
+ if(0/*ISCHAR(t)*/){
+ load_acc(f,&p->q1,t);
+ store_acc(f,&p->z,t);
+ }else{
+ // TODO: PGS: Use AXYZ for 32-bit copy if appropriate
+ // TOGO: PGS: Consider using AXYZ for load, even for 16 or 24-bit values
+ if(!zmleq(p->q2.val.vmax,l2zm(3L))){
+ if(c2m&&(v&0xFF000000)==0){
+ // 65C02 Z is Zero, not a changeable register, so we can
+ // use it to clear upper bytes.
+ // This is NOT the case on 4510/M65, where Z is an index register
+ do_byte4(f,"stz",&p->z,t);
+ }else{
+ do_byte4(f,"lda",&p->q1,t);
+ do_byte4(f,"sta",&p->z,t);
+ }
+ }
+ if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+ if(c2m&&(v&0xFF0000)==0){
+ // 65C02 Z is Zero, not a changeable register, so we can
+ // use it to clear upper bytes.
+ // This is NOT the case on 4510/M65, where Z is an index register
+ do_byte3(f,"stz",&p->z,t);
+ }else{
+ do_byte3(f,"lda",&p->q1,t);
+ do_byte3(f,"sta",&p->z,t);
+ }
+ }
+ if(!zmleq(p->q2.val.vmax,l2zm(1L))){
+ if(c2m&&(v&0xFF00)==0){
+ // 65C02 Z is Zero, not a changeable register, so we can
+ // use it to clear upper bytes.
+ // This is NOT the case on 4510/M65, where Z is an index register
+ do_hibyte(f,"stz",&p->z,t);
+ }else{
+ load_hibyte(f,&p->q1,t);
+ store_hibyte(f,&p->z,t);
+ }
+ }
+ if(c2m&&(v&0xFF)==0){
+ // 65C02 Z is Zero, not a changeable register, so we can
+ // use it to clear upper bytes.
+ // This is NOT the case on 4510/M65, where Z is an index register
+ do_lobyte(f,"stz",&p->z,t);
+ }else{
+ if(isreg(q1)&&ISIDX(p->q1.reg)){
+ store_reg(f,p->q1.reg,&p->z,CHAR);
+ }else if(isreg(z)&&ISIDX(p->z.reg)){
+ load_reg(f,p->z.reg,&p->q1,t);
+ }else{
+ load_lobyte(f,&p->q1,t);
+ store_lobyte(f,&p->z,t);
+ }
+ }
+ }
+ }
+ continue;
+ }
+ if(c==ADDRESS){
+ long o=real_offset(&p->q1);
+ get_acc(f,p,CHAR);
+ emit(f,"\tlda\t%s\n",mregnames[fp1]);
+ if(o){
+ emit(f,"\tclc\n");
+ if((o&255)!=0)
+ emit(f,"\tadc\t#%ld\n",real_offset(&p->q1)&255);
+ }
+ store_lobyte(f,&p->z,t);
+ if(isacc(z)) emit(f,"\tpha\n");
+ emit(f,"\tlda\t%s\n",mregnames[fp2]);
+ if(o!=0)
+ emit(f,"\tadc\t#%ld\n",real_offset(&p->q1)>>8&255);
+ store_hibyte(f,&p->z,t);
+ if(isacc(z)) emit(f,"\tpla\n");
+ continue;
+ }
+
+ if(c==COMPARE||c==TEST){
+ IC *branch=p->next;
+ int pacc=0,bc,bout;
+ while(branch){
+ if(branch->code>=BEQ&&branch->code<BRA)
+ break;
+ if(branch->code!=FREEREG&&branch->code!=ALLOCREG&&branch->code!=NOP)
+ ierror(0);
+ branch=branch->next;
+ }
+ bc=branch->code;
+ bout=branch->typf;
+ if(c==TEST){
+ p->q2.flags=KONST;
+ gval.vmax=Z0;
+ eval_const(&gval,MAXINT);
+ insert_const(&p->q2.val,t);
+ }
+ if((bc==BLE||bc==BGT)&&(p->q2.flags&(DREFOBJ|KONST))==KONST){
+ eval_const(&p->q2.val,t);
+ if(!zmeqto(vmax,l2zm(255L))){
+ vmax=zmadd(vmax,Z1);
+ gval.vmax=vmax;
+ eval_const(&gval,t);
+ insert_const(&p->q2.val,t);
+ if(bc==BLE) bc=BLT; else bc=BGE;
+ branch->code=bc;
+ }
+ }
+ if(ieee&&ISFLOAT(t)){
+ if(!ieee) ierror(0);
+ t&=NQ;
+ if(regs[LAST_PAIR]) ierror(0);
+ regs[LAST_PAIR]=1;
+ if(regs[ra]||regs[rax])
+ ierror(0);
+ load_address(f,LAST_PAIR,&p->q2,t);
+ BSET(regused,t3);
+ BSET(regused,t4);
+ emit(f,"\tjsr\t%s__fload%c\n",idprefix,(t==FLOAT?'s':'d'));
+ yval=NOVAL;
+ load_address(f,LAST_PAIR,&p->q1,t);
+ emit(f,"\tjsr\t%s__fcmp%c\n",idprefix,(t==FLOAT?'s':'d'));
+ yval=NOVAL;
+ regs[LAST_PAIR]=0;
+ if(bc==BLT||bc==BLE)
+ emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+ else if(bc==BGT|bc==BGE)
+ emit(f,"\tbvs\t%s%d\n",labprefix,bout);
+ if(bc==BEQ||bc==BLE||bc==BGE)
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ continue;
+ }
+ if(ISCHAR(t)){
+ char *s=0;
+ if(isreg(q1)&&ISIDX(p->q1.reg)&&!indirect(&p->q2)&&(bc==BEQ||bc==BNE||(t&UNSIGNED))){
+ static char buf[4]="cpr";
+ s=buf;s[2]=mregnames[p->q1.reg][0];
+ }else{
+ if(pacc=cmp_get_acc(f,p,branch))
+ bout=++label;
+ load_acc(f,&p->q1,t);
+ if(bc==BEQ||bc==BNE||(t&UNSIGNED)){
+ s="cmp";
+ }else{
+ if(bc==BLT||bc==BGE)
+ emit(f,"\tsec\n");
+ else
+ emit(f,"\tclc\n");
+ s="sbc";
+ }
+ }
+ if(c==TEST)
+ emit(f,"\t%s\t#0\n",s);
+ else
+ do_lobyte(f,s,&p->q2,t);
+ if(bc==BEQ)
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ else if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ else if(t&UNSIGNED){
+ if(bc==BLT)
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ else if(bc==BGE)
+ emit(f,"\tbcs\t%s%d\n",labprefix,bout);
+ else if(bc==BLE){
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ }else if(bc==BGT){
+ emit(f,";\n\tbeq\t%s%d\n",labprefix,++label);
+ emit(f,"\tbcs\t%s%d\n",labprefix,bout);
+ emit(f,"%s%d:\n",labprefix,label);
+ }else
+ ierror(0);
+ }else{
+ emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+ emit(f,"\teor\t#128\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(bc==BLT||bc==BLE)
+ emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+ else
+ emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+ }
+ if(pacc){
+ reload_acc(f);
+ add_cmplist(bout,branch->typf,pacc);
+ }
+ continue;
+ }else if(bc==BEQ||bc==BNE||(t&UNSIGNED)||ISFPOINTER(t)){
+ int in=0;
+ if(pacc=cmp_get_acc(f,p,branch))
+ bout=++label;
+
+ // PGS Check for special cases of comparing to constants
+ if(!(ISLONG(t)||ISFPOINTER(t)||isacc(q1))) {
+ // Is a 16-bit value
+ if (p->q2.flags&KONST) {
+ if (!(p->q2.flags&DREFOBJ)) {
+ eval_const(&p->q2.val,t);
+ if(ISFLOAT(t)) cnv_fp();
+ if (zm2l(vmax)==0x100) {
+ if (bc==BGE) {
+ // >= $100 we can check by just reading the 2nd byte
+ // If non-zero, then we take the branch
+ do_hibyte(f,"lda",&p->q1,t);
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ continue;
+ } else if (bc==BLT) {
+ // <$100 we can check by just reading the 2nd byte
+ // And if zero, then we take the branch
+ do_hibyte(f,"lda",&p->q1,t);
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ continue;
+ }
+ } else if (zm2l(vmax)<0x100) {
+ // Values <$100 we can do almost as simply, but we have to
+ // also check the low byte for exceptions.
+ // XXX PGS TODO
+
+ }
+ }
+ }
+ }
+
+ // Far-Pointers are 32-bit on M65
+ if(ISLONG(t)||ISFPOINTER(t)){
+ do_byte4(f,"lda",&p->q1,t);
+ if(c==TEST)
+ emit(f,"\tcmp\t#0\n");
+ else
+ do_byte4(f,"cmp",&p->q2,t);
+ if(bc==BEQ)
+ emit(f,"\tbne\t%s%d\n",labprefix,in=++label);
+ else if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ else if(bc==BLT||bc==BLE){
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ emit(f,"\tbne\t%s%d\n",labprefix,in=++label);
+ }else if(bc==BGE||bc==BGT){
+ emit(f,"\tbcc\t%s%d\n",labprefix,in=++label);
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ }else
+ ierror(0);
+ }
+ if(ISLONG(t)||ISFPOINTER(t)){
+ do_byte3(f,"lda",&p->q1,t);
+ if(c==TEST)
+ emit(f,"\tcmp\t#0\n");
+ else
+ do_byte3(f,"cmp",&p->q2,t);
+ if(bc==BEQ)
+ emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+ else if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ else if(bc==BLT||bc==BLE){
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+ }else if(bc==BGE||bc==BGT){
+ emit(f,"\tbcc\t%s%d\n",labprefix,in?in:(in=++label));
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ }else
+ ierror(0);
+ }
+ if(isacc(q1)){
+ if(!indirect(&p->q2)){
+ do_hibyte(f,"cpx",&p->q2,t);
+ }else{
+ int r=get_reg(f,p,CHAR);
+ emit(f,"\tpha\n");
+ load_hibyte(f,&p->q2,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ emit(f,"\tpla\n");
+ emit(f,"\tcpx\t%s\n",mregnames[r]);
+ }
+ }else{
+ load_hibyte(f,&p->q1,t);
+ if(c==TEST)
+ emit(f,"\tcmp\t#0\n");
+ else
+ do_hibyte(f,"cmp",&p->q2,t);
+ }
+ if(bc==BEQ)
+ emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+ else if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ else if(bc==BLT||bc==BLE){
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+ }else if(bc==BGE||bc==BGT){
+ emit(f,"\tbcc\t%s%d\n",labprefix,in?in:(in=++label));
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ }else
+ ierror(0);
+ load_lobyte(f,&p->q1,t);
+ if(c==TEST)
+ emit(f,"\tcmp\t#0\n");
+ else
+ do_lobyte(f,"cmp",&p->q2,t);
+ if(bc==BEQ)
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ else if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ else if(bc==BLT)
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ else if(bc==BGE)
+ emit(f,"\tbcs\t%s%d\n",labprefix,bout);
+ else if(bc==BLE){
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ }else if(bc==BGT){
+ emit(f,"\tbcc\t%s%d\n",labprefix,in);
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ }else
+ ierror(0);
+ if(in)
+ emit(f,"%s%d:\n",labprefix,in);
+ if(pacc){
+ reload_acc(f);
+ add_cmplist(bout,branch->typf,pacc);
+ }
+ continue;
+ }else{
+ if(bc==BGT||bc==BLE){
+ obj o;
+ if(isacc(q1)){
+ int r;
+ if(pacc=cmp_get_acc(f,p,branch))
+ bout=++label;
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ load_lobyte(f,&p->q2,t);
+ emit(f,"\tcmp\t%s\n",mregnames[r]);
+ emit(f,"\tstx\t%s\n",mregnames[r]);
+ load_hibyte(f,&p->q2,t);
+ emit(f,"\tsbc\t%s\n",mregnames[r]);
+ emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+ emit(f,"\teor\t#128\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(bc==BGT)
+ emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+ else
+ emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+ if(pacc){
+ reload_acc(f);
+ add_cmplist(bout,branch->typf,pacc);
+ }
+ continue;
+ }else{
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ if(bc==BGT) bc=BLT; else bc=BGE;
+ }
+ }
+ if(pacc=cmp_get_acc(f,p,branch))
+ bout=++label;
+ if(ISLONG(t)){
+ load_lobyte(f,&p->q1,t);
+ do_lobyte(f,"cmp",&p->q2,t);
+ load_hibyte(f,&p->q1,t);
+ do_hibyte(f,"sbc",&p->q2,t);
+ do_byte3(f,"lda",&p->q1,t);
+ do_byte3(f,"sbc",&p->q2,t);
+ do_byte4(f,"lda",&p->q1,t);
+ do_byte4(f,"sbc",&p->q2,t);
+ }else{
+ load_lobyte(f,&p->q1,t);
+ do_lobyte(f,"cmp",&p->q2,t);
+ load_hibyte(f,&p->q1,t);
+ do_hibyte(f,"sbc",&p->q2,t);
+ }
+ emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+ emit(f,"\teor\t#128\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(bc==BLT)
+ emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+ else if(bc==BGE)
+ emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+ else
+ ierror(0);
+ if(pacc){
+ reload_acc(f);
+ add_cmplist(bout,branch->typf,pacc);
+ }
+ continue;
+ }
+ ierror(0);
+ }
+ if((c==ADD||c==SUB||c==ADDI2P||c==SUBIFP)&&compare_objects(&p->q1,&p->z)&&(!indirect(&p->q1)||(isreg(q1)&&ISIDX(p->q1.reg)))&&isconst(q2)&&!isacc(z)){
+ long l;
+ eval_const(&p->q2.val,q2typ(p));
+ l=zm2l(vmax);
+ if(c==ADDI2P/*&&(t2&NQ)==POINTER*/) {c=ADD;t=UNSIGNED|INT;}
+ if(c==SUBIFP/*&&(t2&NQ)==POINTER*/) {c=SUB;t=UNSIGNED|INT;}
+ if(c==SUB||c==SUBIFP) l=-l;
+ /*TODO: allow larger types */
+ if(l<3&&l>-3&&(t&NQ)<=INT){
+ if(l<0){
+ get_acc(f,p,CHAR);
+ incmem(f,&p->z,t,SUB,-l);
+ }else
+ incmem(f,&p->z,t,ADD,l);
+ continue;
+ }
+ }
+
+ if((c==LSHIFT||c==RSHIFT)&&isreg(q1)&&isreg(z)&&isconst(q2)&&p->q1.reg==p->z.reg&&p->z.reg!=ra&&p->z.reg!=rax){
+ long l;
+ eval_const(&p->q2.val,q2typ(p));
+ l=zm2l(vmax);
+ /*TODO: allow larger types */
+ if(l<5&&(t&NQ)<=INT){
+ if(c==RSHIFT&&!(t&UNSIGNED))
+ get_acc(f,p,CHAR);
+ incmem(f,&p->z,t,c,l);
+ continue;
+ }
+ }
+
+ if(c==LSHIFT||c==RSHIFT){
+ long l=-1;int loop=0,r,r2,r3,outl=0;
+ if(isconst(q2)){
+ eval_const(&p->q2.val,q2typ(p));
+ l=zm2l(vmax);
+ loop=0;
+ }else
+ loop=1;
+ if(l>=0&&optsize){
+ if(c==LSHIFT&&(l&7)>6)
+ loop=1;
+ else if(c==RSHIFT&&(t&UNSIGNED)&&(l&7)>3)
+ loop=1;
+ else if(c==RSHIFT&&!(t&UNSIGNED)&&(l&7)>2)
+ loop=1;
+ }
+
+ if(!ISCHAR(t))
+ r=get_reg(f,p,CHAR);
+ if(ISLONG(t)){
+ r2=get_reg(f,p,CHAR);
+ r3=get_reg(f,p,CHAR);
+ }
+ if(ISLONG(t)){
+ get_acc(f,p,CHAR);
+ if(l>=24){
+ if(c==LSHIFT){
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ emit(f,"\tlda\t#0\n");
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ }else if(c==RSHIFT&&!(t&UNSIGNED)){
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ sety(f,0);
+ emit(f,"\tcmp\t#0\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdey\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tsty\t%s\n",mregnames[r]);
+ emit(f,"\tsty\t%s\n",mregnames[r2]);
+ emit(f,"\ttya\n");
+ yval=NOVAL;
+ }else{
+ emit(f,"\tlda\t#0\n");
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ do_byte4(f,"lda",&p->q1,t);
+
+ }
+ }else if(l>=16){
+ if(c==LSHIFT){
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ emit(f,"\tlda\t#0\n");
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ }else if(c==RSHIFT&&!(t&UNSIGNED)){
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ sety(f,0);
+ emit(f,"\tcmp\t#0\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdey\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tsty\t%s\n",mregnames[r]);
+ emit(f,"\ttya\n");
+ yval=NOVAL;
+ }else{
+ emit(f,"\tlda\t#0\n");
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ do_byte3(f,"lda",&p->q1,t);
+
+ }
+ }else if(l>=8){
+ if(c==LSHIFT){
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ emit(f,"\tlda\t#0\n");
+ }else if(c==RSHIFT&&!(t&UNSIGNED)){
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ sety(f,0);
+ emit(f,"\tcmp\t#0\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdey\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\ttya\n");
+ yval=NOVAL;
+ }else{
+ emit(f,"\tlda\t#0\n");
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ load_hibyte(f,&p->q1,t);
+
+ }
+ }else if(c==RSHIFT&&!(t&UNSIGNED)){
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ do_byte4(f,"lda",&p->q1,t);
+ }else{
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ load_lobyte(f,&p->q1,t);
+ }
+ }else
+ get_acc(f,p,t);
+ if(!ISLONG(t)){
+ if(l>=8){
+ if(!ISSHORT(t)) ierror(0);
+ if(c==LSHIFT){
+ if(indirect(&p->q1)){
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\ttax\n");
+ emit(f,"\tlda\t#0\n");
+ }else{
+ if(isacc(q1))
+ emit(f,"\ttax\n");
+ else
+ do_lobyte(f,"ldx",&p->q1,t);
+ emit(f,"\tlda\t#0\n");
+ }
+ }else{
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tldx\t#0\n");
+ if(!(t&UNSIGNED)){
+ emit(f,"\tcmp\t#0\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdex\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }
+ }else
+ load_acc(f,&p->q1,t);
+ }
+ if(ISSHORT(t))
+ emit(f,"\tstx\t%s\n",mregnames[r]);
+ if(l>=0) l&=7;
+ if(loop){
+ if(l>=0)
+ sety(f,l);
+ else{
+ if(indirect(&p->q2)){
+ emit(f,"\tpha\n");
+ load_lobyte(f,&p->q2,q2typ(p));
+ emit(f,"\ttay\n");
+ emit(f,"\tpla\n");
+ emit(f,"\tcpy\t#0\n");
+ }else{
+ emit(f,"\tldy\t");
+ emit_lobyte(f,&p->q2,q2typ(p));
+ emit(f,"\n");
+ }
+ outl=++label;
+ emit(f,"\tbeq\t%s%d\n",labprefix,outl);
+ }
+ emit(f,"%s%d:\n",labprefix,++label);
+ }else{
+ if(ISCHAR(t))
+ l&=7;
+ else if(ISSHORT(t))
+ l&=15;
+ else
+ l&=31;
+ }
+ while(l>0||loop){
+ if(c==LSHIFT){
+ emit(f,"\tasl\n");
+ if(!ISCHAR(t))
+ emit(f,"\trol\t%s\n",mregnames[r]);
+ if(ISLONG(t)){
+ emit(f,"\trol\t%s\n",mregnames[r2]);
+ emit(f,"\trol\t%s\n",mregnames[r3]);
+ }
+ }else if(t&UNSIGNED){
+ emit(f,"\tclc\n");
+ if(ISLONG(t)){
+ emit(f,"\tror\t%s\n",mregnames[r3]);
+ emit(f,"\tror\t%s\n",mregnames[r2]);
+ }
+ if(!ISCHAR(t))
+ emit(f,"\tror\t%s\n",mregnames[r]);
+ emit(f,"\tror\n");
+ }else{
+ if(ISLONG(t)){
+ emit(f,"\tcmp\t#128\n");
+ emit(f,"\tror\n");
+ emit(f,"\tror\t%s\n",mregnames[r]);
+ emit(f,"\tror\t%s\n",mregnames[r2]);
+ emit(f,"\tror\t%s\n",mregnames[r3]);
+ }else{
+ if(!ISCHAR(t)){
+ emit(f,"\tcpx\t#128\n");
+ emit(f,"\tror\t%s\n",mregnames[r]);
+ }else
+ emit(f,"\tcmp\t#128\n");
+ emit(f,"\tror\n");
+ }
+ }
+ if(loop){
+ emit(f,"\tdey\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,label);
+ if(outl) emit(f,"%s%d:\n",labprefix,outl);
+ yval=0;
+ break;
+ }
+ l--;
+ }
+ if(ISLONG(t)){
+ if(c==RSHIFT&&!(t&UNSIGNED)){
+ do_byte4(f,"sta",&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r]);
+ do_byte3(f,"sta",&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r2]);
+ store_hibyte(f,&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r3]);
+ store_lobyte(f,&p->z,t);
+ }else{
+ store_lobyte(f,&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r]);
+ store_hibyte(f,&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r2]);
+ do_byte3(f,"sta",&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r3]);
+ do_byte4(f,"sta",&p->z,t);
+ }
+ }else{
+ if(!ISCHAR(t))
+ emit(f,"\tldx\t%s\n",mregnames[r]);
+ if(ISCHAR(t)||indirect(&p->z))
+ store_acc(f,&p->z,t);
+ else{
+ store_lobyte(f,&p->z,t);
+ if(!isreg(z)||p->z.reg!=rax){
+ emit(f,"\tstx\t");
+ emit_hibyte(f,&p->z,t);
+ emit(f,"\n");
+ }
+ }
+ }
+ continue;
+ }
+
+ if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)||c==ADDI2P||c==SUBIFP){
+ char *s;int t2=t,pt=p->typf2;
+ if(!isacc(z))
+ get_acc(f,p,CHAR);
+ if(c==ADDI2P||c==SUBIFP){
+ if(c==ADDI2P) c=ADD; else c=SUB;
+ t=UNSIGNED|INT;
+ if((pt&NQ)==POINTER&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q1.val,POINTER);
+ insert_const(&p->q1.val,UNSIGNED|INT);
+ }
+ }
+ if(c>=OR&&c<=AND)
+ s=logicals[c-OR];
+ else
+ s=arithmetics[c-LSHIFT];
+
+ if(ISFLOAT(t)){
+ if(!ieee) ierror(0);
+ t&=NQ;
+ if(regs[LAST_PAIR]) ierror(0);
+ get_acc(f,p,INT);
+ regs[LAST_PAIR]=1;
+ load_address(f,LAST_PAIR,&p->q1,t);
+ BSET(regused,t3);
+ BSET(regused,t4);
+ emit(f,"\tjsr\t%s__fload%c\n",idprefix,(t==FLOAT?'s':'d'));
+ yval=NOVAL;
+ load_address(f,LAST_PAIR,&p->q2,t);
+ emit(f,"\tjsr\t%s__f%s%c\n",idprefix,ename[c],(t==FLOAT?'s':'d'));
+ yval=NOVAL;
+ load_address(f,LAST_PAIR,&p->z,t);
+ emit(f,"\tjsr\t%s__fstore%c\n",idprefix,(t==FLOAT?'s':'d'));
+ yval=NOVAL;
+ regs[LAST_PAIR]=0;
+ continue;
+ }else if(ISLONG(t)){
+ if(c==ADD) emit(f,"\tclc\n");
+ if(c==SUB) emit(f,"\tsec\n");
+ load_lobyte(f,&p->q1,t);
+ do_lobyte(f,s,&p->q2,t);
+ store_lobyte(f,&p->z,t);
+ load_hibyte(f,&p->q1,t);
+ do_hibyte(f,s,&p->q2,t);
+ store_hibyte(f,&p->z,t);
+ do_byte3(f,"lda",&p->q1,t);
+ do_byte3(f,s,&p->q2,t);
+ do_byte3(f,"sta",&p->z,t);
+ do_byte4(f,"lda",&p->q1,t);
+ do_byte4(f,s,&p->q2,t);
+ do_byte4(f,"sta",&p->z,t);
+ continue;
+ }else if(ISCHAR(t)){
+ load_acc(f,&p->q1,t);
+ if(has_inc_a&&(c==ADD||c==SUB)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,t);
+ if(zmeqto(vmax,Z1)||zmeqto(vmax,l2zm(2L))){
+ if(zmeqto(vmax,l2zm(2L)))
+ emit(f,"\t%s\n",c==ADD?"ina":"dea");
+ emit(f,"\t%s\n",c==ADD?"ina":"dea");
+ store_acc(f,&p->z,t);
+ continue;
+ }
+ }
+ if(c==ADD) emit(f,"\tclc\n");
+ if(c==SUB) emit(f,"\tsec\n");
+ if(isreg(q2)&&ISIDX(p->q2.reg)){
+ int r=get_reg(f,p,CHAR);
+ emit(f,"\tst%s\t%s\n",mregnames[p->q2.reg],mregnames[r]);
+ p->q2.flags=REG;
+ p->q2.reg=r;
+ }
+ do_lobyte(f,s,&p->q2,t);
+ store_acc(f,&p->z,t);
+ }else if(c==ADD||c==SUB){
+ int a,r;long l=1;
+ if(isconst(q2)){
+ eval_const(&p->q2.val,t2);
+ l=zm2l(vmax);
+ l&=0xff00;
+ }
+ if(isreg(z)&&p->z.reg==rax) a=1; else a=0;
+ if((t2&NU)==CHAR&&(p->q2.flags&(KONST|DREFOBJ))!=KONST){
+ emit(f,"\tldx\t#0\n");
+ }
+ if((t2&NU)==CHAR&&(p->q2.flags&(KONST|DREFOBJ))!=KONST){
+ load_lobyte(f,&p->q2,t);
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdex\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(c==ADD){
+ if(c==ADD) emit(f,"\tclc\n"); else emit(f,"\tsec\n");
+ do_lobyte(f,s,&p->q1,t);
+ if(isacc(z))
+ emit(f,"\tpha\n");
+ else
+ store_lobyte(f,&p->z,t);
+ emit(f,"\ttxa\n");
+ do_hibyte(f,s,&p->q1,t);
+ store_hibyte(f,&p->z,t);
+ if(ISFPOINTER(pt)&&!compare_objects(&p->q1,&p->z)){
+ do_byte3(f,"lda",&p->q1,pt);
+ do_byte3(f,"sta",&p->z,pt);
+ }
+ if(isacc(z))
+ emit(f,"\tpla\n");
+ continue;
+ }
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tstx\t%s\n",mregnames[r]);
+ }
+ load_lobyte(f,&p->q1,t);
+ if(c==ADD) emit(f,"\tclc\n"); else emit(f,"\tsec\n");
+ do_lobyte(f,s,&p->q2,t2);
+ store_lobyte(f,&p->z,t);
+ if(l==0&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg){
+ if(c==ADD){
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ if(a)
+ emit(f,"\tinx\n");
+ else{
+ /*if(!reg_pair(p->z.reg,&rp)) ierror(0);*/
+ emit(f,"\tinc\t%s+1\n",mregnames[p->z.reg]);
+ }
+ }else{
+ emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+ if(a)
+ emit(f,"\tdex\n");
+ else{
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ emit(f,"\tdec\t%s\n",mregnames[rp.r2]);
+ }
+ }
+ emit(f,"%s%d:\n",labprefix,label);
+ }else{
+ if(a==1) emit(f,"\tpha\n");
+ if((t2&NQ)==CHAR){
+ if(t2&UNSIGNED){
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\t%s\t#0\n",s);
+ }else{
+ load_hibyte(f,&p->q1,t);
+ if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,t2);
+ if(zmleq(Z0,vmax))
+ emit(f,"\t%s\t#0\n",s);
+ else
+ emit(f,"\t%s\t#255\n",s);
+ }else{
+ emit(f,"\t%s\t%s\n",s,mregnames[r]);
+ }
+ }
+ }else{
+ load_hibyte(f,&p->q1,t);
+ do_hibyte(f,s,&p->q2,t2);
+ }
+ store_hibyte(f,&p->z,t);
+ if(a==1) emit(f,"\tpla\n");
+ if(ISFPOINTER(pt)&&p->code!=SUBPFP){
+ if(!compare_objects(&p->q1,&p->z)){
+ do_byte3(f,"lda",&p->q1,FPOINTER);
+ do_byte3(f,"sta",&p->z,FPOINTER);
+ }
+ }
+ }
+ }else{
+ if(isacc(q1))
+ emit(f,"\tpha\n");
+ load_hibyte(f,&p->q1,t);
+ do_hibyte(f,s,&p->q2,t);
+ store_hibyte(f,&p->z,t);
+ if(isacc(q1))
+ emit(f,"\tpla\n");
+ load_lobyte(f,&p->q1,t);
+ do_lobyte(f,s,&p->q2,t);
+ store_lobyte(f,&p->z,t);
+ }
+ continue;
+ }
+ pric2(stdout,p);
+ ierror(0);
+ }
+
+ function_bottom(f,v,localsize);
+
+ for(c=1;c<=MAXR;c++){
+ if(regsa[c]||regused[c]){
+ BSET(regs_modified,c);
+ }
+ }
+
+ if(stack_valid){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=stack;
+ }
+ }
+
+ free_IC(mi);
+
+ emit(f,"; stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int code,int typ)
+{
+ if(code==COMPARE/*||code==MULT*/||code==ADD||code==SUB||code==AND||code==OR||code==XOR||code==LSHIFT||code==RSHIFT||code==MINUS||code==KOMPLEMENT||code==NEGATION)
+ return 1;
+
+ return 0;
+}
+
+static int fattr(type *p,char *s)
+{
+ if(p->attr&&strstr(p->attr,s))
+ return 1;
+ if(p->next)
+ return fattr(p->next,s);
+ else
+ return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+ int f;
+
+ if(vararg)
+ return 0;
+ f=t->flags&NQ;
+ if(OLDFP&&ISFLOAT(f)) return 0;
+ if(d&&fattr(d,"__stackparms__"))
+ return 0;
+ if(d&&fattr(d,"__cc65__")){
+ m->regs++;
+ printf("arg=%d cnt=%d\n",m->regs,d->exact->count);
+ if(m->regs==d->exact->count-1){
+ if(ISCHAR(t->flags))
+ return ra;
+ if(ISSHORT(t->flags))
+ return rax;
+ }
+ return 0;
+ }
+ if(ISCHAR(f)){
+ if(!t->exact){
+ if(m->regs>=GPR_ARGS-1)
+ return 0;
+ f=FIRST_GPR+m->regs;
+ m->regs+=2;
+ return f;
+ }else{
+ if(m->regs>=GPR_ARGS)
+ return 0;
+ else
+ return FIRST_GPR+m->regs++;
+ }
+ }
+ if(ISSHORT(f)||f==POINTER){
+ if(m->regs>=GPR_ARGS-1)
+ return 0;
+ else{
+ if(m->regs&1) m->regs+=1;
+ m->regs+=2;
+ return FIRST_PAIR+m->regs/2-1;
+ }
+ }
+ if(f==FPOINTER||f==LONG||f==FLOAT||(!ieee&&(f==DOUBLE||f==LDOUBLE))){
+ if(m->bregs>=4)
+ return 0;
+ else
+ return FIRST_BIG+m->bregs++;
+ }
+ if(f==LLONG||(ieee&&(f==DOUBLE||f==LDOUBLE))){
+ if(m->bregs>=3)
+ return 0;
+ else{
+ if(m->bregs&1) m->bregs++;
+ m->bregs+=2;
+ return FIRST_BIGP+m->bregs/2-1;
+ }
+ }
+ return 0;
+}
+
+int handle_pragma(const char *s)
+{
+ static char sec[SECLEN];
+ int i;
+ if(sscanf(s,"section %127s",sec)==1){
+ if(!strcmp(sec,"default"))
+ use_sec=0;
+ else
+ use_sec=sec;
+ return 1;
+ }
+ if(sscanf(s,"bank %d",&i)==1){
+ use_bank=i;
+ return 1;
+ }
+}
+void cleanup_cg(FILE *f)
+{
+ int i;
+ struct fpconstlist *p=firstfpc;
+
+ if(f&&p){
+ emit(f,rodataname);emit(f,"\n");
+ section=RODATA;
+ }
+ while(p=firstfpc){
+ emit(f,"%s%d:\n\tword\t",labprefix,p->label);
+ if(ieee)
+ emit_ieee(f,&p->val,p->t);
+ else{
+ int words=zm2l(sizetab[p->t&NQ])/2;
+ eval_const(&p->val,p->t);
+ if(ISFLOAT(p->t)) cnv_fp();
+ for(i=0;i<words;i++){
+ emit(f,"%ld",zm2l(vmax)&0xffff);
+ if(i<words-1){emit(f,",");vmax=zmrshift(vmax,l2zm(16L));}
+ }
+ emit(f,"\n");
+ /*emit(f,"%ld,%ld\n",zm2l(vmax)&0xffff,zm2l(zmrshift(vmax,l2zm(16L)))&0xffff);*/
+ }
+ firstfpc=p->next;
+ free(p);
+ }
+
+ emit(f,"\tzpage\t%s\n",mregnames[sp]);
+ for(i=FIRST_GPR;i<=LAST_GPR;i++)
+ emit(f,"\tzpage\t%s\n",mregnames[i]);
+ for(i=FIRST_BIG;i<=LAST_BIG;i++)
+ emit(f,"\tzpage\t%s\n",mregnames[i]);
+
+}
+void cleanup_db(FILE *f)
+{
+ if(f) section=-1;
+}
+
+static char *zops[]={
+ "adc","and","asl","bit","eor","lda","ora",
+ "tax","txa","tay","tya","sbc"};
+
+static int setszflag(char *op)
+{
+ int i;
+ for(i=0;i<sizeof(zops)/sizeof(zops[0]);i++)
+ if(!strcmp(op,zops[i]))
+ return 1;
+ return 0;
+}
+
+static char *zxops[]={
+ "tax","txa","ldx","inx","dex"};
+
+static int setszxflag(char *op)
+{
+ int i;
+ for(i=0;i<sizeof(zxops)/sizeof(zxops[0]);i++)
+ if(!strcmp(op,zxops[i]))
+ return 1;
+ return 0;
+}
+
+enum peepf { NEEDSAME = 1, REMOVE1ST = 2};
+struct peeps {char *s1,*s2,*r;enum peepf flags;};
+
+
+
+int emit_peephole(void)
+{
+ int entries,i,j;
+ char *asmline[EMIT_BUF_DEPTH];
+ char buf1[1024],buf2[1024];
+ char op1[8],op2[8];
+ static char ca[1024],cx[1024],cy[1024],cz[1024];
+ static int rm,disabled;
+
+ fprintf(stderr,"Called emit_peephole()\n");
+
+ static struct peeps elim[]={
+ "lda","sta",0,NEEDSAME,
+ "ldx","stx",0,NEEDSAME,
+ "sta","sta",0,NEEDSAME,
+ "stx","stx",0,NEEDSAME,
+ "sta","lda",0,NEEDSAME,
+ "stx","ldx",0,NEEDSAME,
+ "txa","tax",0,0,
+ "tax","txa",0,0,
+ "lda","lda",0,REMOVE1ST,
+ "ldx","ldx",0,REMOVE1ST,
+ "ldy","ldy",0,REMOVE1ST,
+ "ldz","ldz",0,REMOVE1ST,
+ "lda","pla",0,REMOVE1ST,
+ "lda","txa",0,REMOVE1ST,
+ "lda","tya",0,REMOVE1ST,
+ "ldx","tax",0,REMOVE1ST,
+ "ldy","tay",0,REMOVE1ST,
+ "tay","ldy",0,REMOVE1ST,
+ "taz","ldz",0,REMOVE1ST,
+ "tax","ldx",0,REMOVE1ST,
+ "txa","lda",0,REMOVE1ST,
+ "tya","lda",0,REMOVE1ST,
+ "tza","lda",0,REMOVE1ST,
+ "lda","ldx","\ttax\n",NEEDSAME,
+ "lda","ldy","\ttay\n",NEEDSAME,
+ "ldx","lda","\ttxa\n",NEEDSAME,
+ "ldy","lda","\ttya\n",NEEDSAME,
+ "sta","ldx","\ttax\n",NEEDSAME,
+ "sta","ldy","\ttay\n",NEEDSAME,
+ "stx","lda","\ttxa\n",NEEDSAME,
+ "sty","lda","\ttya\n",NEEDSAME,
+
+ };
+
+ if(nopeep) return 0;
+
+ i=emit_l;
+ if(emit_f==0)
+ entries=i-emit_f+1;
+ else
+ entries=EMIT_BUF_DEPTH;
+ asmline[0]=emit_buffer[i];
+
+ if(!strcmp(asmline[0],";startinline\n")) disabled=1;
+ if(!strcmp(asmline[0],";endinline\n")) disabled=0;
+ if(disabled) return 0;
+
+ buf1[0]=0;op1[0]=0;
+ if((j=sscanf(asmline[0]," %6s %999s",op1,buf1))>=1){
+ printf("a=%s x=%s y=%s, z=%s\n",ca,cx,cy,cz);
+ printf("\t\t%s %s\n",op1,buf1);
+ if(!strcmp(op1,"sta")) {
+ // Work out when we are accessing variables on the stack
+ if (!strcmp(buf1,"(sp),y")) {
+ // We invalidate this when Y changes
+ snprintf(ca,1024,"(sp),y",cy);
+ }
+ } else if(!strcmp(op1,"sta")){
+ // Remove writes to wherever A was loaded from
+ if (!strcmp(buf1,ca)) {
+ remove_asm();
+ return rm=1;
+ }
+ } else if(!strcmp(op1,"lda")){
+ if(buf1[0]=='#'){
+ if(!rm&&!strcmp(buf1,ca)){remove_asm();return rm=1;}
+ strcpy(ca,buf1);
+ }else {
+ // Work out when we are accessing variables on the stack
+ if (!strcmp(buf1,"(sp),y")) {
+ if(!strcmp(buf1,ca)){
+ remove_asm();
+ return rm=1;
+ }
+ snprintf(ca,1024,"(sp),y",cy);
+ }
+ // Similarly look for register loads
+ // We can sometimes remove some of those, too.
+ if ((strlen(buf1)>1)&&(buf1[0]=='r')) {
+ if (strcmp(ca,buf1))
+ snprintf(ca,1024,"%s",buf1);
+ else {
+ // Don't re-load A with the same contents it already has
+ remove_asm();
+ return rm=1;
+ }
+ }
+ }
+ }else if(!strcmp(op1,"ldx")){
+ if(buf1[0]=='#'){
+ if(!rm&&!strcmp(buf1,cx)){remove_asm();return rm=1;}
+ strcpy(cx,buf1);
+ }else cx[0]=0;
+ }else if(!strcmp(op1,"ldy")){
+ if(buf1[0]=='#'){
+ if(!rm&&!strcmp(buf1,cy)){remove_asm();return rm=1;}
+ strcpy(cy,buf1);
+ }else cy[0]=0;
+ }else if(!strcmp(op1,"ldz")){
+ if(buf1[0]=='#'){
+ if(!rm&&!strcmp(buf1,cz)){remove_asm();return rm=1;}
+ strcpy(cz,buf1);
+ }else cz[0]=0;
+ }else{
+ // TODO: PGS: Add the AXYZ operations to the clobber lists.
+ // Will we need to handle them specially?
+ static char clobbernone[]="clc cld cli clv cmp cpx cpy dec inc nop pha php plp sec sed sei sta stx sty stz";
+ static char clobbera[]="adc and asl eor lsr ora pla rol ror sbc txa tya tza neg";
+ static char clobberx[]="dex inx tax tsx";
+ static char clobbery[]="dey iny tay";
+ static char clobberz[]="dez inz taz";
+ if(strstr(clobbernone,op1)){
+ // Invalidate A holding a stack variable byte if SP changes
+ if (strstr(buf1,"sp")) {
+ printf("buf1='%s'\n",buf1);
+ if (strstr(ca,"(sp),y")) ca[0]=0;
+ }
+ }else if(strstr(clobbera,op1))
+ ca[0]=0;
+ else if(strstr(clobberx,op1))
+ cx[0]=0;
+ else if(strstr(clobbery,op1)) {
+ cy[0]=0;
+ // Invalidate A holding a stack variable byte if Y changes
+ if (strstr(ca,"(sp),y")) ca[0]=0;
+ }
+ else if(strstr(clobberz,op1))
+ cz[0]=0;
+ else
+ ca[0]=cx[0]=cy[0]=cz[0]=0;
+ }
+ }else{
+ ca[0]=cx[0]=cy[0]=cz[0]=0;
+ }
+
+ rm=0;
+
+ if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"and")&&!strcmp(buf1,"#0")){
+ strcpy(asmline[0],"\tlda\t#0\n");
+ return rm=1;
+ }
+
+ if(entries>=2){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[1]=emit_buffer[i];
+
+
+ if(!strcmp(asmline[0],"; volatile barrier\n")&&!strcmp(asmline[0],asmline[1])){
+ remove_asm();
+ return rm=1;
+ }
+
+ if(sscanf(asmline[0]," %6s",op1)==1&&!strcmp(op1,"rts")&&
+ sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&!strcmp(op2,"jsr")){
+ sprintf(asmline[1],"\tjmp\t%s\n",buf2);
+ remove_asm();
+ return rm=1;
+ }
+
+ for(j=0;j<sizeof(elim)/sizeof(elim[0]);j++){
+ if(elim[j].flags&NEEDSAME){
+ if(sscanf(asmline[0]," %6s %999s",op2,buf2)==2&&
+ sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&
+ !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)&&
+ !strcmp(buf1,buf2)){
+ if(elim[j].r){
+ strcpy(asmline[0],elim[j].r);
+ }else{
+ if(elim[j].flags&REMOVE1ST)
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ }
+ return rm=1;
+ }
+ }else{
+ if(sscanf(asmline[1]," %6s",op1)==1&&
+ sscanf(asmline[0]," %6s",op2)==1&&
+ !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)){
+ if(elim[j].flags&REMOVE1ST)
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return rm=1;
+ }
+ }
+ }
+
+
+ }
+
+ if(entries>=3){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[2]=emit_buffer[i];
+ if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2){
+#if 0
+ if(!strcmp(op1,"lda")&&buf1[0]=='#'){
+ if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+ !strcmp(op2,"sta")){
+ if(sscanf(asmline[2]," %6s %999s",op2,buf2)==2&&
+ !strcmp(op2,"lda")&&!strcmp(buf1,buf2)){
+ remove_asm();
+ return rm=1;
+ }
+ }
+ }
+#endif
+ if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){
+ if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+ !strcmp(op2,"cmp")&&!strcmp(buf2,"#0")){
+ if(sscanf(asmline[2]," %6s",op2)==1&&
+ setszflag(op2)){
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return rm=1;
+ }
+ }
+ }
+ if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){
+ if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+ !strcmp(op2,"cpx")&&!strcmp(buf2,"#0")){
+ if(sscanf(asmline[2]," %6s",op2)==1&&
+ setszxflag(op2)){
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return rm=1;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Return name of library function, if this node should be
+ implemented via libcall. */
+char *use_libcall(int c,int t,int t2)
+{
+ static char fname[16];
+ char *ret=0;
+
+ if(c==COMPARE){
+ if((t&NQ)==LLONG||(ISFLOAT(t)&&!ieee)){
+ sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }else{
+ t&=NU;
+ t2&=NU;
+ if(ISSHORT(t)&&c!=MULT&&c!=DIV&&c!=MOD&&!ISFLOAT(t2))
+ return 0;
+ if(ISLONG(t)&&c!=MULT&&c!=DIV&&c!=MOD&&!ISFLOAT(t2))
+ return 0;
+
+ if(!ieee&&ISFLOAT(t)) t=FLOAT;
+ if(t==LDOUBLE) t=DOUBLE;
+ if(t2==LDOUBLE) t2=DOUBLE;
+ if(!ieee&&ISFLOAT(t2)) t2=FLOAT;
+ if(c==CONVERT){
+ if(t==t2) return 0;
+ if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+ if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+
+ if(ISFLOAT(t)){
+ sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64);
+ ret=fname;
+ }
+ if(ISFLOAT(t2)){
+ sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+ if((t&NQ)==INT||(t&NQ)==LONG||(t&NQ)==LLONG||(!ieee&&ISFLOAT(t))){
+ if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+ if(t==(UNSIGNED|LLONG)&&(c==MULT||c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint64",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==LLONG){
+ sprintf(fname,"__%sint64",ename[c]);
+ ret=fname;
+ }else if(t==(UNSIGNED|LONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint32",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==LONG){
+ sprintf(fname,"__%sint32",ename[c]);
+ ret=fname;
+ }else if(t==(UNSIGNED|INT)&&(c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint16",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==INT){
+ sprintf(fname,"__%sint16",ename[c]);
+ ret=fname;
+ }else{
+ sprintf(fname,"__%s%s%s%ld",ename[c],(t&UNSIGNED)?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+int pointer_varadr(Var *v)
+{
+ int b=bank(v);
+ if(b>=0&&b!=bankcnum&&!NOBANKVARS){
+ if(cur_funcv&&bank(cur_funcv)!=b)
+ return FPOINTER;
+ }
+ return pointer_type(v->vtyp);
+}
+
+int pointer_type(struct Typ *p)
+{
+ struct Typ *merk=p;
+ if(!p) ierror(0);
+ if(LARGE) return FPOINTER;
+ while(ISARRAY(p->flags)||ISFUNC(p->flags)) p=p->next;
+ if(p->attr){
+ char *s;
+ if(strstr(p->attr,STR_HUGE)) return HPOINTER;
+ if(strstr(p->attr,STR_FAR)) return FPOINTER;
+ if(strstr(p->attr,STR_NEAR)) return POINTER;
+ }
+ return POINTER;
+}
+
+unsigned char cbmconv(unsigned char x)
+{
+ static unsigned char ctab[256]={
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x14,0x09,0x0D,0x11,0x93,0x0A,0x0E,0x0F,
+ 0x10,0x0B,0x12,0x13,0x08,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+ 0x40,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0x5B,0xBF,0x5D,0x5E,0xA4,
+ 0xAD,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0xB3,0xDD,0xAB,0xB1,0xDF,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+ 0x90,0x91,0x92,0x0C,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+ 0xA0,0xA1,0xA2,0xA3,0x5F,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0x7D,0xAC,0x60,0xAE,0xAF,
+ 0xB0,0x7E,0xB2,0x7B,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0x5C,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0xDC,0x7C,0xDE,0x7F,
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+ };
+
+ static unsigned char atab[]={0xfd,8,0x7f,0x9b,11,0x7d};
+
+ if(cbmascii)
+ return ctab[x&255];
+ else if(atascii&&x>=7&&x<=12)
+ return atab[x-7];
+ else
+ return x;
+}
+
+void insert_const(union atyps *p,int t)
+/* Traegt Konstante in entprechendes Feld ein. */
+{
+ if(!p) ierror(0);
+/* *p = (union atyps) 0 ; /* rfi: clear unused bits */
+ t&=NU;
+ if(t==CHAR) {p->vchar=vchar;return;}
+ if(t==SHORT) {p->vshort=vshort;return;}
+ if(t==INT) {p->vint=vint;return;}
+ if(t==LONG) {p->vlong=vlong;return;}
+ if(t==LLONG) {p->vllong=vllong;return;}
+ if(t==MAXINT) {p->vmax=vmax;return;}
+ if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+ if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+ if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+ if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+ if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+ if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+ if(t==FLOAT) {p->vfloat=vfloat;return;}
+ if(t==DOUBLE) {p->vdouble=vdouble;return;}
+ if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+ if(t==POINTER) {p->vuint=vuint;return;}
+ if(t==FPOINTER||t==HPOINTER) {p->vulong=vulong;return;}
+}
+
+void eval_const(union atyps *p,int t)
+/* Weist bestimmten globalen Variablen Wert einer CEXPR zu. */
+{
+ int f=t&NQ;
+ if(!p) ierror(0);
+ if(f==MAXINT||(f>=CHAR&&f<=LLONG)){
+ if(!(t&UNSIGNED)){
+ if(f==CHAR) vmax=zc2zm(p->vchar);
+ else if(f==SHORT)vmax=zs2zm(p->vshort);
+ else if(f==INT) vmax=zi2zm(p->vint);
+ else if(f==LONG) vmax=zl2zm(p->vlong);
+ else if(f==LLONG) vmax=zll2zm(p->vllong);
+ else if(f==MAXINT) vmax=p->vmax;
+ else ierror(0);
+ vumax=zm2zum(vmax);
+ vldouble=zm2zld(vmax);
+ }else{
+ if(f==CHAR) vumax=zuc2zum(p->vuchar);
+ else if(f==SHORT)vumax=zus2zum(p->vushort);
+ else if(f==INT) vumax=zui2zum(p->vuint);
+ else if(f==LONG) vumax=zul2zum(p->vulong);
+ else if(f==LLONG) vumax=zull2zum(p->vullong);
+ else if(f==MAXINT) vumax=p->vumax;
+ else ierror(0);
+ vmax=zum2zm(vumax);
+ vldouble=zum2zld(vumax);
+ }
+ }else{
+ if(ISPOINTER(f)){
+ if(f==POINTER)
+ vumax=zui2zum(p->vuint);
+ else
+ vumax=zul2zum(p->vulong);
+ vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+ }else{
+ if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+ else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+ else vldouble=p->vldouble;
+ vmax=zld2zm(vldouble);
+ vumax=zld2zum(vldouble);
+ }
+ }
+ vfloat=zld2zf(vldouble);
+ vdouble=zld2zd(vldouble);
+ vuchar=zum2zuc(vumax);
+ vushort=zum2zus(vumax);
+ vuint=zum2zui(vumax);
+ vulong=zum2zul(vumax);
+ vullong=zum2zull(vumax);
+ vchar=zm2zc(vmax);
+ vshort=zm2zs(vmax);
+ vint=zm2zi(vmax);
+ vlong=zm2zl(vmax);
+ vllong=zm2zll(vmax);
+}
+
+void printval(FILE *f,union atyps *p,int t)
+/* Gibt atyps aus. */
+{
+ t&=NU;
+ if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+ if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+ if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+ if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+ if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+ if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+ if(t==(UNSIGNED|INT)||t==POINTER){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+ if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+ if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+ if(t==MAXINT) printzm(f,p->vmax);
+ if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax);
+}
+
+void emitval(FILE *f,union atyps *p,int t)
+/* Gibt atyps aus. */
+{
+ t&=NU;
+ if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+ if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+ if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+ if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+ if(t==LDOUBLE){emitzld(f,p->vldouble);}
+ if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+ if(t==(UNSIGNED|INT)||t==POINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+ if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+ if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+ if(t==MAXINT) emitzm(f,p->vmax);
+ if(t==(UNSIGNED|MAXINT)) emitzum(f,p->vumax);
+}
+
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+ char *attr;
+ while(p){
+ if(ISPOINTER(p->flags)){
+ p->flags=((p->flags&~NU)|POINTER_TYPE(p->next));
+ if(attr=p->next->attr){
+ if(strstr(attr,STR_NEAR))
+ p->flags=((p->flags&~NU)|POINTER);
+ if(strstr(attr,STR_FAR))
+ p->flags=((p->flags&~NU)|FPOINTER);
+ if(strstr(attr,STR_HUGE))
+ p->flags=((p->flags&~NU)|HPOINTER);
+ }
+ }
+ p=p->next;
+ }
+}
+
+void add_var_hook_post(Var *v)
+{
+ if(use_sec&&(v->storage_class==STATIC||v->storage_class==EXTERN)){
+ char buf[SECLEN+32];
+ sprintf(buf,"section(\"%s\");",use_sec);
+ add_attr(&v->vattr,buf);
+ }
+ if(use_bank>=0&&(v->storage_class==STATIC||v->storage_class==EXTERN)){
+ char buf[64];
+ /*sprintf(buf,"section(\"bank%d\");bank(%d)",use_bank,use_bank);*/
+ sprintf(buf,"bank(%d)",use_bank);
+ add_attr(&v->vattr,buf);
+ }
+}
+
+int decide_reverse(zmax v)
+{
+ if(zmeqto(v,Z1)||zmeqto(v,l2zm(2L)))
+ return 1;
+ if(optspeed)
+ if(zmeqto(v,l2zm(4L))||zmeqto(v,l2zm(8L))||zmeqto(v,l2zm(256L))||zmeqto(v,l2zm(512L)))
+ return 1;
+
+ return 0;
+}
+
+static int is_single_eff_ic(struct IC *p)
+{
+ struct Var *v,*idx;
+ if(p->code!=ADDI2P||(p->typf2&NQ)!=POINTER)
+ return 0;
+ if(!(p->q2.flags&KONST)){
+ if((p->typf&NU)!=(UNSIGNED|CHAR))
+ return 0;
+ if((p->q2.flags&(VAR|DREFOBJ))!=VAR)
+ return 0;
+ if(p->q2.v->storage_class!=AUTO&&p->q2.v->storage_class!=REGISTER)
+ return 0;
+ idx=p->q2.v;
+ }else{
+ idx=0;
+ eval_const(&p->q2.val,p->typf);
+ /* TODO: more precise check considering data type useful? */
+ if(!zmleq(vumax,l2zm(255L)))
+ return 0;
+ return 1;
+ }
+ if(p->q1.flags&DREFOBJ)
+ return 0;
+ if((p->z.flags&(VAR|DREFOBJ))!=VAR)
+ return 0;
+ if(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)
+ return 0;
+ v=p->z.v;
+ for(p=p->next;p;p=p->next){
+ int c=p->code;
+ if(c==LABEL||(c>=BEQ&&c<=BRA))
+ return 1; /* TODO: how elaborate should we test? */
+ if((p->q1.flags&VAR)&&p->q1.v==v){
+ if(p->q1.flags&DREFOBJ)
+ return 1;
+ else
+ return 0;
+ }
+ if((p->q2.flags&VAR)&&p->q2.v==v){
+ if(p->q2.flags&DREFOBJ)
+ return 1;
+ else
+ return 0;
+ }
+ if((p->z.flags&VAR)&&p->z.v==v){
+ if(p->z.flags&DREFOBJ)
+ return 1;
+ else
+ return 0;
+ }
+ if((p->z.flags&VAR)&&p->z.v==idx)
+ return 0;
+ }
+ return 0;
+}
+
+void mark_eff_ics(void)
+{
+ struct IC *p;
+ for(p=first_ic;p;p=p->next){
+ if(is_single_eff_ic(p))
+ p->flags|=EFF_IC;
+ else
+ p->flags&=~EFF_IC;
+ }
+}
diff --git a/machines/m65/machine.dt b/machines/m65/machine.dt
new file mode 100755
index 0000000..eab38c9
--- /dev/null
+++ b/machines/m65/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S16BULE S16BUBE
+
+
diff --git a/machines/m65/machine.h b/machines/m65/machine.h
new file mode 100755
index 0000000..ca54ff9
--- /dev/null
+++ b/machines/m65/machine.h
@@ -0,0 +1,269 @@
+/* MEGA65 / 45GS02 backend for vbcc
+ (c) Volker Barthelmann 2020
+ (c) Paul Gardner-Stephen 2020
+
+*/
+
+/* built-time configurable options: */
+#define NUM_GPRS 32
+#define NUM_PAIRS (NUM_GPRS/2)
+#define NUM_BIG 4
+#define NUM_BIGP (NUM_BIG/2)
+#define FIXED_SP 1
+
+#include "dt.h"
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef BOOL
+#undef MAXINT
+#undef MAX_TYPE
+
+#define CHAR 1
+#define SHORT 2
+#define INT 3
+#define LONG 4
+#define LLONG 5
+#define FLOAT 6
+#define DOUBLE 7
+#define LDOUBLE 8
+#define VOID 9
+#define POINTER 10
+#define FPOINTER 11
+#define HPOINTER 12
+#define ARRAY 13
+#define STRUCT 14
+#define UNION 15
+#define ENUM 16
+#define FUNKT 17
+#define BOOL 18
+
+#define MAXINT 19
+
+#define MAX_TYPE MAXINT
+
+
+#define POINTER_TYPE(x) pointer_type(x)
+#define POINTER_VARADR(x) pointer_varadr(x)
+extern int pointer_type();
+extern int pointer_varadr();
+#define ISPOINTER(x) ((x&NQ)>=POINTER&&(x&NQ)<=HPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=CHAR&&(x&NQ)<=HPOINTER)
+#define ISINT(x) ((x&NQ)>=CHAR&&(x&NQ)<=LLONG)
+#define PTRDIFF_T(x) ((x)==HPOINTER?LONG:INT)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+ zchar vchar;
+ zuchar vuchar;
+ zshort vshort;
+ zushort vushort;
+ zint vint;
+ zuint vuint;
+ zlong vlong;
+ zulong vulong;
+ zllong vllong;
+ zullong vullong;
+ zmax vmax;
+ zumax vumax;
+ zfloat vfloat;
+ zdouble vdouble;
+ zldouble vldouble;
+};
+
+
+/* internally used by the backend */
+#define FIRST_GPR 10
+#define LAST_GPR (FIRST_GPR+NUM_GPRS-1)
+#define FIRST_PAIR (LAST_GPR+1)
+#define LAST_PAIR (FIRST_PAIR+NUM_PAIRS-1)
+#define FIRST_BIG (LAST_PAIR+1)
+#define LAST_BIG (FIRST_BIG+NUM_BIG-1)
+#define FIRST_BIGP (LAST_BIG+1)
+#define LAST_BIGP (FIRST_BIGP+NUM_BIGP-1)
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Currently possible are (const,gpr) and (gpr,gpr) */
+struct AddressingMode{
+ int flags;
+ int base;
+ int idx;
+ long offset;
+ void *v;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR LAST_BIGP
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 20
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P CHAR
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 0
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 1
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+/* Parameters are sometimes passed in registers without __reg. */
+#define HAVE_REGPARMS 1
+
+/* Parameters on the stack should be pushed in order rather than */
+/* in reverse order. */
+#define ORDERED_PUSH FIXED_SP
+
+/* Structure for reg_parm(). */
+struct reg_handle{
+ int regs;
+ int bregs;
+};
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt
+ register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 3
+// MEGA65 CPU has one wait-state on reads when CPU is at full speed
+#define cost_load_reg(x,y) 5
+#define cost_save_reg(x,y) 4
+#define cost_pushpop_reg(x) 6
+
+/* size of buffer for asm-output, this can be used to do
+ peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 8
+
+/* We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+ optimizations on code which can already be implemented by efficient
+ assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we have additional types */
+#define HAVE_EXT_TYPES
+#define HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#define HAVE_INT_SIZET 1
+
+/* we do not need register-pairs */
+#define HAVE_REGPAIRS 1
+
+
+/* do not create CONVERT ICs from integers smaller than int to floats */
+#define MIN_INT_TO_FLOAT_TYPE INT
+
+/* do not create CONVERT ICs from floats to ints smaller than int */
+#define MIN_FLOAT_TO_INT_TYPE INT
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 0
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 0
+
+/* convert multiplications/division by powers of two to shifts */
+#define HAVE_POF2OPT 1
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+/* Use char for return of comparison libcalls */
+#define LIBCALL_CMPTYPE CHAR
+
+/* We prefer BNE rather than BGT. */
+#define HAVE_WANTBNE 1
+
+#define BESTCOPYT CHAR
+
+#define HAVE_AOS4 1
+
+#define CHARCONV(x) cbmconv(x)
+unsigned char cbmconv(unsigned char);
+
+#define ALLOCVLA_REG FIRST_PAIR
+#define ALLOCVLA_INLINEASM "\tlda\tsp\n"\
+ "\tsec\n"\
+ "\tsbc\tr0\n"\
+ "\tsta\tsp\n"\
+ "\tlda\tsp+1\n"\
+ "\tsbc\tr1\n"\
+ "\tsta\tsp+1\n"\
+ "\tlda\tsp\n"\
+ "\tclc\n"\
+ "\tldx\tsp+1\n"\
+ "\tadc\t#___fo\n"\
+ "\tbcc\t*+3\n"\
+ "\tinx\n"
+
+#define FREEVLA_REG FIRST_PAIR
+#define FREEVLA_INLINEASM "\tlda\tr0\n"\
+ "\tsta\tsp\n"\
+ "\tlda\tr1\n"\
+ "\tsta\tsp+1\n"
+
+#define OLDSPVLA_INLINEASM "\tlda\tsp+1\n"\
+ "\ttax\n"\
+ "\tlda\tsp"
+
+#define FPVLA_REG (LAST_PAIR-2)
+
+#define HAVE_TARGET_VARHOOK_POST 1
+
+#define HAVE_DECIDE_REVERSE 1
+
+#define HAVE_TARGET_EFF_IC 1
diff --git a/machines/m65/merge.c b/machines/m65/merge.c
new file mode 100755
index 0000000..2e43d73
--- /dev/null
+++ b/machines/m65/merge.c
@@ -0,0 +1,4995 @@
+/* MEGA65 45GS02 backend for vbcc
+ (c) Volker Barthelmann 2020
+ (c) Paul Gardner-Stephen 2020
+
+*/
+
+#include "supp.h"
+#include "vbc.h"
+
+#include <math.h>
+
+static char FILE_[]=__FILE__;
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc 45GS02 (MEGA65) code-generator V0.1 (c) in 2020 by Volker Barthelmann, Paul Gardner-Stephen";
+
+/* Commandline-flags the code-generator accepts:
+ 0: just a flag
+ VALFLAG: a value must be specified
+ STRINGFLAG: a string can be specified
+ FUNCFLAG: a function will be called
+ apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]={0,0,
+ VALFLAG,0,0,
+ 0,0,
+ VALFLAG,VALFLAG,0,0,
+ VALFLAG,0,0,0,
+ 0,0,0,
+ 0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+ they collide with the frontend */
+char *g_flags_name[MAXGF]={"std-syntax","no-rax",
+ "volatile-regs","ieee","no-peephole",
+ "cbmascii","softstack",
+ "reg-args","int-args","mainargs","no-bank-vars",
+ "common-banknr","btmp-zpage","oldfp","large",
+ "glob-acc","avoid-bank-switch","manual-banking",
+ "atascii"};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. will be initialized in init_cg(),
+ register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+ estimated cost-saving can be obtained by several registers, the
+ one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__interrupt","__zpage","__nocpr",0};
+
+#define INTERRUPT 1
+#define ZPAGE 2
+#define NOCOMPRESS 4
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+#define STDSYNTAX (g_flags[0]&USEDFLAG)
+#define NORAX (g_flags[1]&USEDFLAG)
+#define VOL_GPRS ((g_flags[2]&USEDFLAG)?g_flags_val[2].l:NUM_GPRS/2)
+#define IEEE (g_flags[3]&USEDFLAG)
+#define NOPEEP (g_flags[4]&USEDFLAG)
+#define CBMASCII (g_flags[5]&USEDFLAG)
+#define SOFTSTACK (g_flags[6]&USEDFLAG)
+#define GPR_ARGS ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:8)
+#define MAINARGS (g_flags[9]&USEDFLAG)
+#define NOBANKVARS (g_flags[10]&USEDFLAG)
+#define COMMONBANK ((g_flags[11]&USEDFLAG)?g_flags_val[11].l:0)
+#define BIGZPAGE (g_flags[12]&USEDFLAG)
+#define OLDFP (g_flags[13]&USEDFLAG)
+#define LARGE (g_flags[14]&USEDFLAG)
+#define GLOBACC (g_flags[15]&USEDFLAG)
+#define NOSWITCH (g_flags[16]&USEDFLAG)
+#define NOBANKING (g_flags[17]&USEDFLAG)
+#define ATASCII (g_flags[18]&USEDFLAG)
+
+
+
+#define STR_NEAR "near"
+#define STR_FAR "far"
+#define STR_HUGE "huge"
+
+#define PLA (-1)
+#define JMPIND (-2)
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isacc(x) (isreg(x)&&(p->x.reg==ra||p->x.reg==rax))
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+#define isptr(r) ((r)>=FIRST_PAIR&&(r)<=LAST_PAIR)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"ora","eor","and"};
+static char *arithmetics[]={"slw","srw","adc","sbc","mullw","divw","mod"};
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]= {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,2,4,8,4,4,4,0,2,3,3,0,0,0,1,0};
+static char *mregnames[MAXR+1];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","char","short","int","long","long long",
+ "float","double","long double","void",
+ "near-pointer","far-pointer","huge-pointer",
+ "array","struct","union","enum","function"};
+
+
+/* used to initialize regtyp[] */
+static struct Typ ityp={INT},ctyp={CHAR},ftyp={FLOAT},lltyp={LLONG};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+ "__m65__",
+ "__SIZE_T_INT",
+ "__bank(x)=__vattr(\"bank(\"#x\")\")",
+ "__far=__attr(\"far\")",
+ "__near=__attr(\"near\")",
+ "__huge=__attr(\"huge\")",
+ 0};
+
+/* special registers */
+static int ra=1, rx=2, ry=3, rz=4, sp1=5,sp2=6,sp=7,fp,fp1,fp2;
+static int t4=LAST_GPR,t3=LAST_GPR-1,t2=LAST_GPR-2,t1=LAST_GPR-3;
+static int rax=8;
+static int raxyz=9;
+static int yval;
+#define NOVAL 1000
+
+static int t1,t2,f1,f2; /*tODO: remove*/
+
+static int pushedacc,pushedx,nopeep,cbmascii,atascii,ieee;
+static int pass;
+static int libsave;
+static struct rpair rp2;
+static int cbank;
+static Var bankv;
+static int bankvoffset;
+static int bankcnum;
+static obj zstore;
+static int zstoreflag;
+
+#define SECLEN 128
+char *use_sec;
+int use_bank=-1;
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* perhaps provide version with 8bit int? */
+#define ISCHAR(t) ((t&NQ)==CHAR)
+#define ISSHORT(t) ((t&NQ)==SHORT||(t&NQ)==INT||(t&NQ)==POINTER)
+#define ISFPOINTER(t) ((t&NQ)==FPOINTER)
+#define ISLONG(t) ((t&NQ)==LONG)
+#define ISLLONG(t) ((t&NQ)==LLONG)
+
+/* am */
+#define IMM_IND 1
+#define GPR_IND 2
+#define ABS_IND 3
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\tsection\ttext",
+ *dataname="\tsection\tdata",
+ *bssname="\tsection\tbss",
+ *rodataname="\tsection\trodata";
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+/* variables to calculate the size and partitioning of the stack-frame
+ in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+
+static long localsize,rsavesize,rscnt,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+ stack-pointer; we use a layout like this:
+ ------------------------------------------------
+ | arguments to this function |
+ ------------------------------------------------
+ | caller-save registers [size=rsavesize] |
+ ------------------------------------------------
+ | local variables [size=localsize] |
+ ------------------------------------------------
+ | arguments to called functions [size=argsize] |
+ ------------------------------------------------
+ All sizes will be aligned as necessary.
+ In the case of FIXED_SP, the stack-pointer will be adjusted at
+ function-entry to leave enough space for the arguments and have it
+ aligned to 16 bytes. Therefore, when calling a function, the
+ stack-pointer is always aligned to 16 bytes.
+ For a moving stack-pointer, the stack-pointer will usually point
+ to the bottom of the area for local variables, but will move while
+ arguments are put on the stack.
+
+ This is just an example layout. Other layouts are also possible.
+*/
+
+static int bank(Var *v)
+{
+ char *s=v->vattr;
+ int n,r;
+ if(!NOBANKING&&s&&(s=strstr(s,"bank("))){
+ if(sscanf(s+5,"%i",&n)==1)
+ return n;
+ }
+ return -1;
+}
+
+static void ebank(FILE *f,int b)
+{
+ if(b>=0) emit(f,"%d",b);
+ emit(f,"\n");
+}
+
+static long real_offset(struct obj *o)
+{
+ long off=zm2l(o->v->offset);
+ if(off<0){
+ /* function parameter */
+ off=localsize+rsavesize-off-zm2l(maxalign);
+ }
+
+ off+=argsize;
+ off+=zm2l(o->val.vmax);
+ return off;
+}
+
+/* Initializes an addressing-mode structure and returns a pointer to
+ that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ am.offset=offset;
+ return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+ char *sec;
+ if(v->tattr&ZPAGE){
+ emit(f,"\tsection\tzpage\n");
+ }else{
+ if(!v->vattr) return 0;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return 0;
+ sec+=strlen("section(");
+ emit(f,"\tsection\t");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ }
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+
+
+#define chk_coll(x) do{if((x)==r||(x)==r1||(x)==r2) return 0; \
+ if(reg_pair((x),&rp)&&(rp.r1==r||rp.r2==r)) return 0;}while(0)
+
+static int scratch(IC *p,int r)
+{
+ int r1,r2;
+ if(!p) return 1;
+ if(reg_pair(r,&rp)){
+ r1=rp.r1;
+ r2=rp.r2;
+ }else{
+ r1=0;
+ r2=0;
+ }
+ if(isreg(z)&&p->z.reg==r){
+ if(!(p->q2.flags®))
+ return 1;
+ if(p->q2.reg==r||p->q2.reg==r1||p->q2.reg==r2)
+ return 0;
+ if(reg_pair(p->q2.reg,&rp))
+ if(rp.r1==r||rp.r2==r)
+ return 0;
+ return 1;
+ }
+ while(p){
+ if(p->code==LABEL||p->code==CALL)
+ return 0;
+ if(p->code>=BEQ&&p->code<=BRA)
+ return 0;
+ if(p->code==FREEREG||p->code==ALLOCREG){
+ if(p->q1.reg==r)
+ return 1;
+ if(reg_pair(p->q1.reg,&rp)&&(rp.r1==r||rp.r2==r))
+ return 1;
+ }
+ if(p->q1.am) chk_coll(p->q1.am->base);
+ if(p->q2.am) chk_coll(p->q2.am->base);
+ if(p->z.am) chk_coll(p->z.am->base);
+ if(p->q1.flags®) chk_coll(p->q1.reg);
+ if(p->q2.flags®) chk_coll(p->q2.reg);
+ if(p->z.flags®){
+ if(p->z.flags&DREFOBJ)
+ chk_coll(p->z.reg);
+ else{
+ if(p->z.reg==r)
+ return 1;
+ if(reg_pair(p->z.reg,&rp)&&(rp.r1==r||rp.r2==r))
+ return 1;
+ }
+ }
+
+ p=p->next;
+ }
+ return 1;
+}
+
+static int rsavecur;
+static int in_isr;
+
+static int get_reg(FILE *f,IC *p,int t)
+{
+ int r,r1,r2,pass,flag;
+
+ for(pass=0;pass<5;pass++){
+ for(r=MAXR;r>sp;r--){
+ if(reg_pair(r,&rp)){
+ r1=rp.r1;
+ r2=rp.r2;
+ }else{
+ r1=0;
+ r2=0;
+ }
+ if((pass==0||pass==3)&&(!regscratch[r]||in_isr))
+ continue;
+ if(pass<3){
+ if(regs[r]) continue;
+ if(r1&&(regs[r1]||regs[r2])) continue;
+ }
+ if(pass==2&&!(regs[r]&4))
+ continue;
+ if((p->q1.flags®)&&(p->q1.reg==r||p->q1.reg==r1||p->q1.reg==r2)) continue;
+ if((p->q2.flags®)&&(p->q2.reg==r||p->q2.reg==r1||p->q2.reg==r2)) continue;
+ if((p->z.flags®)&&(p->z.reg==r||p->z.reg==r1||p->z.reg==r2)) continue;
+ if(regok(r,t,1)){
+ flag=8;
+ if(regs[r]){
+ flag|=2;
+ if(p->code==COMPARE||p->code==TEST)
+ ierror(0);
+ if(regs[ra]){
+ emit(f,"\ttay\n");
+ yval=NOVAL;
+ }
+ if(r1){
+ emit(f,"\tlda\t%s\n",mregnames[r1]);
+ emit(f,"\tpha\n");
+ emit(f,"\tlda\t%s\n",mregnames[r2]);
+ emit(f,"\tpha\n");
+ }else{
+ emit(f,"\tlda\t%s\n",mregnames[r]);
+ emit(f,"\tpha\n");
+ }
+ if(regs[ra])
+ emit(f,"\ttya\n");
+ }
+ if(r1){
+ regs[r1]|=flag;
+ regs[r2]|=flag;
+ }
+ regs[r]|=flag;
+ regused[r]=1;
+ regused[r1]=1;
+ regused[r2]=1;
+ return r;
+ }
+ }
+ }
+ pric2(stdout,p);
+ ierror(0);
+}
+
+static void get_acc(FILE *f, IC *p,int t)
+{
+ int r;
+ if(isacc(z)) return;
+ t&=NQ;
+ if(ISCHAR(t)){
+ if(1/*!isreg(q1)||(p->q1.reg!=ra&&p->q1.reg!=rax)*/){
+ if((regs[ra]||regs[rax])&&!scratch(p,ra)&&!pushedacc){
+ if(optsize||(regs[t1]&®s[t2]&®s[t3]&®s[t4])){
+ emit(f,"\tpha\n");
+ pushedacc=-1;
+ }else{
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ pushedacc=r;
+ }
+ }
+ }
+ }else{
+ if(1/*!isreg(q1)||p->q1.reg!=rax*/){
+ if((regs[ra]||regs[rax])&&(!scratch(p,ra)||!scratch(p,rax))&&!pushedacc){
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ pushedacc=r;
+ }
+ if((regs[rx]||regs[rax])&&!scratch(p,rax)&&!pushedx){
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tstx\t%s\n",mregnames[r]);
+ pushedx=r;
+ }
+ }
+ }
+}
+
+static int cmp_get_acc(FILE *f,IC *p,IC *branch)
+{
+ if(!regs[ra]&&!regs[rax])
+ return 0;
+ if(branch==0&&pushedacc)
+ return 0;
+ if(branch&&isreg(q1)&&(p->q1.reg==ra||p->q1.reg==rax))
+ if(branch->code==BEQ||branch->code==BNE||(p->typf&UNSIGNED))
+ return 0;
+ if(scratch(p,ra))
+ return 0;
+ if(!regs[rx]&&!regs[rax]){
+ emit(f,"\ttax\n");
+ pushedacc=rx;
+ }
+ emit(f,"\tpha\n");
+ pushedacc=-1;
+ return pushedacc;
+}
+
+static void reload_acc_opt(FILE *f,IC *p)
+{
+ if(pushedacc==0) return;
+ if(pushedacc>0){
+ while(p){
+ if(p->code!=FREEREG) break;
+ if(p->q1.reg==ra||p->q1.reg==rax){
+ pushedacc=0;
+ return;
+ }
+ p=p->next;
+ }
+ }
+ if(pushedacc==-1)
+ emit(f,"\tpla\n");
+ else if(pushedacc==rx)
+ emit(f,"\ttxa\n");
+ else if(pushedacc==ry)
+ emit(f,"\ttya\n");
+ else if(pushedacc){
+ emit(f,"\tlda\t%s\n",mregnames[pushedacc]);
+ regs[pushedacc]&=~8;
+ }
+ pushedacc=0;
+}
+
+static void reload_acc(FILE *f)
+{
+ reload_acc_opt(f,0);
+}
+
+static void push(int i)
+{
+ pushed-=i;
+ if(pushed<maxpushed)
+ maxpushed=pushed;
+}
+
+static void pop(int i)
+{
+ pushed+=i;
+ if(pushed>0) ierror(0);
+}
+
+static int indirect(obj *o)
+{
+ if((o->flags&(DREFOBJ|KONST))==DREFOBJ)
+ return 1;
+ if((o->flags&(REG|VAR))!=VAR)
+ return 0;
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)
+ return 1;
+ return 0;
+}
+
+void convfloat(void)
+{
+}
+
+void sety(FILE *f,int val)
+{
+ if(yval==val)
+ return;
+ if(val-yval==1)
+ emit(f,"\tiny\n");
+ else if(yval-val==1)
+ emit(f,"\tdey\n");
+ else{
+ emit(f,"\tldy\t#%d\n",val);
+ if(val<0||val>255)
+ ierror(0);
+ }
+ yval=val;
+}
+
+static void cnv_fp(void)
+{
+ double d,mant;
+ int exp;
+ unsigned long t;
+
+ if(ieee){
+ vfloat=zld2zf(vldouble);
+ memcpy((void*)&vmax,(void*)&vfloat,4);
+ }else{
+ d=zld2d(vldouble);
+ mant=frexp(d,&exp);
+ exp=(exp+127)&255;
+ t=((unsigned long)(mant*8388608))&0xffffff;
+ t|=((long)exp)<<24;
+
+ t=((t&0xff)<<24)|((t&0xff00)<<8)|((t&0xff0000)>>8)|((t&0xff000000)>>24);
+ vmax=l2zm((long)t);
+ }
+}
+
+static void emit_ieee(FILE *f,union atyps *p,int t)
+{
+ unsigned char *ip=(unsigned char *)&p->vdouble;
+ emit(f,"0x%02x%02x,0x%02x%02x",ip[1],ip[0],ip[3],ip[2]);
+ if(t==DOUBLE||t==LDOUBLE)
+ emit(f,",0x%02x%02x,0x%02x%02x",ip[5],ip[4],ip[7],ip[6]);
+ emit(f,"\n");
+}
+
+static void emit_lobyte(FILE *f,obj *o,int t)
+{
+ if(o->flags&KONST){
+ if(o->flags&DREFOBJ){
+ eval_const(&o->val,o->dtyp);
+ emit(f,"%d",zm2l(vmax));
+ }else{
+ eval_const(&o->val,t);
+ if(ISFLOAT(t)) cnv_fp();
+ emit(f,"#%d",zm2l(vmax)&255);
+ }
+ }else if(o->flags&VARADR){
+ emit(f,"#<(");
+ emit_obj(f,o,t);
+ emit(f,")");
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ if(!reg_pair(o->reg,&rp))
+ emit(f,"%s",mregnames[o->reg]);
+ else
+ emit(f,"%s",mregnames[rp.r1]);
+ }else{
+ emit_obj(f,o,t);
+ }
+}
+
+static void emit_hibyte(FILE *f,obj *o,int t)
+{
+ if(o->flags&KONST){
+ if(o->flags&DREFOBJ){
+ eval_const(&o->val,o->dtyp);
+ emit(f,"%d",zm2l(vmax)+1);
+ }else{
+ eval_const(&o->val,t);
+ if(ISFLOAT(t)) cnv_fp();
+ emit(f,"#%d",(zm2l(vmax)>>8)&255);
+ }
+ }else if(o->flags&VARADR){
+ emit(f,"#>(");
+ emit_obj(f,o,t);
+ emit(f,")");
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg>=FIRST_BIG&&o->reg<=LAST_BIGP){
+ emit(f,"%s+1",mregnames[o->reg]);
+ }else{
+ if(!reg_pair(o->reg,&rp))
+ ierror(0);
+ emit(f,"%s",mregnames[rp.r2]);
+ }
+ }else{
+ if(o->flags&VARADR)
+ emit(f,"#");
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmadd(o->val.vmax,Z1);
+ emit_obj(f,o,t);
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmsub(o->val.vmax,Z1);
+ }
+}
+
+static void emit_byte3(FILE *f,obj *o,int t)
+{
+ if(o->flags&KONST){
+ if(o->flags&DREFOBJ){
+ eval_const(&o->val,o->dtyp);
+ emit(f,"%d",zm2l(vmax)+2);
+ }else{
+ eval_const(&o->val,t);
+ if(ISFLOAT(t)) cnv_fp();
+ emit(f,"#%d",(zm2l(vmax)>>16)&255);
+ }
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ emit(f,"%s+2",mregnames[o->reg]);
+ }else if(o->flags&VARADR){
+ emit(f,"#%d",bank(o->v));
+ }else{
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmadd(o->val.vmax,l2zm(2L));
+ emit_obj(f,o,t);
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmsub(o->val.vmax,l2zm(2L));
+ }
+}
+
+static void emit_byte4(FILE *f,obj *o,int t)
+{
+ if(o->flags&KONST){
+ if(o->flags&DREFOBJ){
+ eval_const(&o->val,o->dtyp);
+ emit(f,"%d",zm2l(vmax)+3);
+ }else{
+ eval_const(&o->val,t);
+ if(ISFLOAT(t)) cnv_fp();
+ emit(f,"#%d",(zm2l(vmax)>>24)&255);
+ }
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ emit(f,"%s+3",mregnames[o->reg]);
+ }else{
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmadd(o->val.vmax,l2zm(3L));
+ emit_obj(f,o,t);
+ if(!(o->flags&DREFOBJ))
+ o->val.vmax=zmsub(o->val.vmax,l2zm(3L));
+ }
+}
+
+static void do_lobyte(FILE *f,char *s,obj *o,int type)
+{
+ if(o->am){
+ if(o->am->flags==IMM_IND)
+ sety(f,o->am->offset);
+ else if(o->am->flags==GPR_IND||o->am->flags==ABS_IND){
+ if(o->am->offset==ra)
+ emit(f,"\ttay\n");
+ else
+ emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+ yval=NOVAL;
+ }else
+ ierror(0);
+ }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+ sety(f,0);
+ }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+ sety(f,(int)real_offset(o));
+ }
+ emit(f,"\t%s\t",s);
+ emit_lobyte(f,o,type);
+ emit(f,"\n");
+}
+
+static void do_hibyte(FILE *f,char *s,obj *o,int type)
+{
+ int ami=0;
+ if(o->am){
+ if(o->am->flags==IMM_IND)
+ sety(f,o->am->offset+1);
+ else if(o->am->flags==ABS_IND){
+ if(o->am->offset==ra)
+ emit(f,"\ttay\n");
+ else
+ emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+ o->am->offset++;ami=1;
+ yval=NOVAL;
+ }else
+ ierror(0);
+ }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+ sety(f,1);
+ }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+ sety(f,(int)real_offset(o)+1);
+ }
+ emit(f,"\t%s\t",s);
+ emit_hibyte(f,o,type);
+ emit(f,"\n");
+ if(ami) o->am->offset--;
+}
+
+static void do_byte3(FILE *f,char *s,obj *o,int type)
+{
+ int ami=0;
+ if(o->am){
+ if(o->am->flags==IMM_IND)
+ sety(f,o->am->offset+2);
+ else if(o->am->flags==ABS_IND){
+ if(o->am->offset==ra)
+ emit(f,"\ttay\n");
+ else
+ emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+ yval=NOVAL;
+ o->am->offset+=2;ami=1;
+ }else
+ ierror(0);
+ }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+ sety(f,2);
+ }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+ sety(f,(int)real_offset(o)+2);
+ }
+ emit(f,"\t%s\t",s);
+ emit_byte3(f,o,type);
+ emit(f,"\n");
+ if(ami) o->am->offset-=2;
+}
+
+static void do_byte4(FILE *f,char *s,obj *o,int type)
+{
+ int ami=0;
+ if(o->am){
+ if(o->am->flags==IMM_IND)
+ sety(f,o->am->offset+3);
+ else if(o->am->flags==ABS_IND){
+ if(o->am->offset==ra)
+ emit(f,"\ttay\n");
+ else
+ emit(f,"\tldy\t%s\n",mregnames[o->am->idx]);
+ yval=NOVAL;
+ o->am->offset+=3;ami=1;
+ }else
+ ierror(0);
+ }else if((o->flags&(DREFOBJ|KONST))==DREFOBJ){
+ sety(f,3);
+ }else if((o->flags&(VAR|REG|VARADR))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)){
+ sety(f,(int)real_offset(o)+3);
+ }
+ emit(f,"\t%s\t",s);
+ emit_byte4(f,o,type);
+ emit(f,"\n");
+ if(ami) o->am->offset-=3;
+}
+
+static void load_lobyte(FILE *f,obj *o,int t)
+{
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg==ra||o->reg==rax)
+ return;
+ if(o->reg==rx){
+ emit(f,"\ttxa\n");
+ return;
+ }
+ }
+ do_lobyte(f,"lda",o,t);
+}
+
+static void load_hibyte(FILE *f,obj *o,int t)
+{
+ if((o->flags®)&&(o->reg==rx||o->reg==rax))
+ emit(f,"\ttxa\n");
+ else
+ do_hibyte(f,"lda",o,t);
+}
+
+static void store_lobyte(FILE *f,obj *o,int t)
+{
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg==ra||o->reg==rax)
+ return;
+ if(o->reg==rx){
+ emit(f,"\ttax\n");
+ return;
+ }
+ }
+ do_lobyte(f,"sta",o,t);
+}
+
+static void store_hibyte(FILE *f,obj *o,int t)
+{
+ if((o->flags®)&&(o->reg==rx||o->reg==rax))
+ emit(f,"\ttax\n");
+ else
+ do_hibyte(f,"sta",o,t);
+}
+
+static void load_acc(FILE *f,obj *o,int type)
+{
+ if((o->flags®)&&(o->reg==ra||o->reg==rax))
+ return;
+ if(!ISCHAR(type)){
+ if(indirect(o)){
+ do_hibyte(f,"lda",o,type);
+ emit(f,"\ttax\n");
+ }else
+ do_hibyte(f,"ldx",o,type);
+ }
+ if((o->flags&(REG|DREFOBJ))==REG&&o->reg==rx)
+ emit(f,"\ttxa\n");
+ else
+ do_lobyte(f,"lda",o,type);
+}
+
+static void store_acc(FILE *f,obj *o,int type)
+{
+ if((o->flags&(DREFOBJ|KONST))==DREFOBJ&&((!(o->flags®))||!isptr(o->reg))){
+ ierror(0);
+ }
+ if((o->flags®)&&(o->reg==ra||o->reg==rax))
+ return;
+ if((o->flags®)&&o->reg==rx){
+ emit(f,"\ttax\n");
+ return;
+ }
+ store_lobyte(f,o,type);
+ if(!ISCHAR(type)){
+ if(indirect(o)){
+ /*TODO: save accu */
+ emit(f,"\ttxa\n");
+ store_hibyte(f,o,type);
+ }else
+ do_hibyte(f,"stx",o,type);
+ }
+}
+
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+ static obj ro;
+ ro.flags=REG;
+ ro.reg=r;
+ load_lobyte(f,o,type);
+ store_lobyte(f,&ro,type);
+ if(!ISCHAR(type)){
+ load_hibyte(f,o,type);
+ store_hibyte(f,&ro,type);
+ }
+}
+
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+ static obj ro;
+ if(r==rx){
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg==rx)
+ return;
+ if(o->reg==ra){
+ emit(f,"\ttxa\n");
+ return;
+ }
+ }
+ }
+ ro.flags=REG;
+ ro.reg=r;
+ if(r!=ra&&r!=rax)
+ load_acc(f,&ro,type);
+ store_acc(f,o,type);
+}
+
+static struct fpconstlist {
+ struct fpconstlist *next;
+ int label;
+ int t;
+ union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+ struct fpconstlist *p=firstfpc;
+ t&=NQ;
+ if(t==LDOUBLE) t=DOUBLE;
+ for(p=firstfpc;p;p=p->next){
+ if(t==p->t){
+ eval_const(&p->val,t);
+ if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+ if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+ if(t==LONG&&zmeqto(vmax,zl2zm(o->val.vlong))) return p->label;
+ if(t==LLONG&&zmeqto(vmax,zll2zm(o->val.vllong))) return p->label;
+ }
+ }
+ p=mymalloc(sizeof(struct fpconstlist));
+ p->next=firstfpc;
+ p->t=t;
+ p->label=++label;
+ p->val=o->val;
+ firstfpc=p;
+ return p->label;
+}
+
+/* generate code to load the address of a local variable into register r */
+static void load_laddr(FILE *f,int r,struct obj *o)
+{
+ long l=real_offset(o);
+ /* assumes acc is available */
+ if(!reg_pair(r,&rp)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[fp]);
+ if(l!=0)
+ emit(f,"\tclc\n");
+ if(l&255)
+ emit(f,"\tadc\t#%ld\n",l&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[fp2]);
+ if(l!=0)
+ emit(f,"\tadc\t#%ld\n",(l>>8)&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int t)
+{
+ if(o->flags&DREFOBJ){
+ o->flags&=~DREFOBJ;
+ load_reg(f,r,o,POINTER);
+ o->flags|=DREFOBJ;
+ }else if((o->flags&(REG|DREFOBJ))==REG){
+ if(!reg_pair(r,&rp)) ierror(0);
+ emit(f,"\tlda\t#>%s\n",mregnames[o->reg]);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tlda\t#<%s\n",mregnames[o->reg]);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ }else if(o->flags&VAR){
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+ load_laddr(f,r,o);
+ }else{
+ o->flags|=VARADR;
+ load_reg(f,r,o,POINTER);
+ o->flags&=~VARADR;
+ }
+ }else if((o->flags&(KONST|DREFOBJ))==KONST){
+ int l=addfpconst(o,t);
+ if(!ieee) ierror(0);
+ if(!reg_pair(r,&rp)) ierror(0);
+ emit(f,"\tlda\t#>%s%d\n",labprefix,l);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tlda\t#<%s%d\n",labprefix,l);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ }else
+ ierror(0);
+}
+
+
+/* Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+
+static void incmem(FILE *f,obj *o,int t,int op,int x)
+{
+ int i;
+ char *s;
+
+ // PGS: All registers and pseudo registers on the M65 target
+ // live in zero-page, so we can use INW and DEW for fast
+ // increment/decrement.
+ if (o->flags®) {
+ switch(op) {
+ case ADD:
+ if(ISCHAR(t)){
+ emit(f,"\tinc\t");
+ emit_obj(f,o,t);
+ emit(f,"\n");
+ } else {
+ emit(f,"\tinw\t");
+ emit_obj(f,o,t);
+ emit(f,"\n");
+ }
+ return;
+ break;
+ case SUB:
+ if(ISCHAR(t)){
+ emit(f,"\tdec\t");
+ emit_obj(f,o,t);
+ emit(f,"\n");
+ } else {
+ emit(f,"\tdew\t");
+ emit_obj(f,o,t);
+ emit(f,"\n");
+ }
+ return;
+ break;
+ }
+ }
+
+ if(op==ADD)
+ s="inc";
+ else if(op==SUB)
+ s="dec";
+ else if(op==LSHIFT)
+ s="asl";
+ else if(op==RSHIFT&&(t&UNSIGNED))
+ s="clc\n\tror";
+ else if(op==RSHIFT){
+ s="cmp\t#128\n\tror";
+ }else
+ ierror(0);
+ if(ISCHAR(t)){
+ for(i=0;i<x;i++){
+ emit(f,"\t%s\t",s);
+ emit_obj(f,o,t);
+ emit(f,"\n");
+ }
+ }else{
+ for(i=0;i<x;i++){
+ if(op==SUB){
+ /* caller mus make sure accu is available */
+ load_lobyte(f,o,t);
+ emit(f,"\tbne\t%s%d\n",labprefix,++label);
+ emit(f,"\tdec\t");
+ emit_hibyte(f,o,t);
+ emit(f,"\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tdec\t");
+ emit_lobyte(f,o,t);
+ emit(f,"\n");
+ }else if(op==ADD){
+ emit(f,"\t%s\t",s);
+ emit_lobyte(f,o,t);
+ emit(f,"\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,++label);
+ emit(f,"\t%s\t",s);
+ emit_hibyte(f,o,t);
+ emit(f,"\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ }else if(op==LSHIFT){
+ // 4510 / 45GS02 have ASW/ROW operations
+ // for left-shifting 16-bit values
+
+ emit(f,"\tasw\t");
+ emit_lobyte(f,o,t);
+ emit(f,"\n");
+
+ }else if(op==RSHIFT&&(t&UNSIGNED)){
+ emit(f,"\tclc\n");
+ emit(f,"\tror\t");
+ emit_hibyte(f,o,t);
+ emit(f,"\n");
+ emit(f,"\tror\t");
+ emit_lobyte(f,o,t);
+ emit(f,"\n");
+ }else if(op==RSHIFT){
+ load_hibyte(f,o,t);
+ emit(f,"\tcmp\t#128\n");
+ emit(f,"\tror\t");
+ emit_hibyte(f,o,t);
+ emit(f,"\n");
+ emit(f,"\tror\t");
+ emit_lobyte(f,o,t);
+ emit(f,"\n");
+ }else{
+ printf("op=%d\n",op);
+ ierror(0);
+ }
+ }
+ }
+}
+
+static void preload_obj(FILE *f,IC *p,obj *o)
+{
+ int r;long of;
+
+ if((p->typf&VOLATILE)||(p->typf2&VOLATILE)||
+ ((p->q1.flags&DREFOBJ)&&(p->q1.dtyp&(VOLATILE|PVOLATILE)))||
+ ((p->q2.flags&DREFOBJ)&&(p->q2.dtyp&(VOLATILE|PVOLATILE)))||
+ ((p->z.flags&DREFOBJ)&&(p->z.dtyp&(VOLATILE|PVOLATILE))))
+ emit(f,"; volatile barrier\n");
+
+
+ if((o->flags&(VAR|REG))==VAR&&(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)&&(of=real_offset(o))+zm2l(szof(o->v->vtyp))>255){
+ r=get_reg(f,p,POINTER);
+ if(o->flags&DREFOBJ)
+ get_acc(f,p,INT);
+ else
+ cmp_get_acc(f,p,0);
+ if(!reg_pair(r,&rp)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[fp1]);
+ emit(f,"\tclc\n");
+ if(of&0xff)
+ emit(f,"\tadc\t#%ld\n",of&0xff);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[fp2]);
+ if(1/*of&0xff00*/)
+ emit(f,"\tadc\t#%ld\n",(of>>8)&0xff);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ o->flags|=REG;
+ o->reg=r;
+ if(o->flags&DREFOBJ){
+ sety(f,0);
+ emit(f,"\tlda\t(%s),y\n",mregnames[r]);
+ emit(f,"\ttxa\n");
+ sety(f,1);
+ emit(f,"\tlda\t(%s),y\n",mregnames[r]);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tstx\t%s\n",mregnames[rp.r1]);
+ }else{
+ o->flags|=DREFOBJ;
+ o->dtyp=POINTER;
+ }
+ }
+
+ if((o->flags&(DREFOBJ|KONST))==DREFOBJ&&(!(o->flags®)||!isptr(o->reg))&&(!(o->flags&VAR)||!(o->v->tattr&ZPAGE))&&!ISFPOINTER(o->dtyp)){
+ cmp_get_acc(f,p,0);
+ r=get_reg(f,p,POINTER);
+ o->flags&=~DREFOBJ;
+ load_reg(f,r,o,POINTER);
+ o->flags|=REG|DREFOBJ;
+ o->reg=r;
+ }
+}
+
+static void far_copy(FILE *f,IC *p)
+{
+ int b;long l;
+ get_acc(f,p,INT);
+ if(p->code==PUSH){
+ if(!reg_pair(LAST_PAIR,&rp)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ if(pushed) emit(f,"\tclc\n");
+ if(pushed&0xff) emit(f,"\tadc\t#%d\n",(pushed&0xff));
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+ if(pushed) emit(f,"\tadc\t#%d\n",((pushed>>8)&0xff));
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ pushed+=zm2l(p->q2.val.vmax);
+ emit(f,"\tldx\t#%d\n",bankcnum);
+ }else if(p->z.flags&DREFOBJ){
+ if(!reg_pair(LAST_PAIR,&rp)) ierror(0);
+ p->z.flags&=~DREFOBJ;
+ load_lobyte(f,&p->z,FPOINTER);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ load_hibyte(f,&p->z,FPOINTER);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ if(indirect(&p->z)){
+ do_byte3(f,"lda",&p->z,FPOINTER);
+ emit(f,"\ttax\n");
+ }else
+ do_byte3(f,"ldx",&p->z,FPOINTER);
+ }else{
+ load_address(f,LAST_PAIR,&p->z,POINTER);
+ b=bank(p->z.v);
+ emit(f,"\tldx\t#%d\n",b>=0?b:bankcnum);
+ }
+ if(p->q1.flags&DREFOBJ){
+ if(!reg_pair(LAST_PAIR-1,&rp)) ierror(0);
+ p->q1.flags&=~DREFOBJ;
+ load_lobyte(f,&p->q1,FPOINTER);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ load_hibyte(f,&p->q1,FPOINTER);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ if(indirect(&p->q1)){
+ do_byte3(f,"lda",&p->q1,FPOINTER);
+ emit(f,"\ttay\n");
+ }else
+ do_byte3(f,"ldy",&p->q1,FPOINTER);
+ }else{
+ load_address(f,LAST_PAIR-1,&p->q1,POINTER);
+ b=bank(p->q1.v);
+ sety(f,b>=0?b:bankcnum);
+ }
+ l=zm2l(p->q2.val.vmax);
+ emit(f,"\tlda\t#%d\n",(l>>8)&0xff);
+ emit(f,"\tsta\t%s__bankcopy_len+1\n",idprefix);
+ emit(f,"\tlda\t#%d\n",(l)&0xff);
+ emit(f,"\tsta\t%s__bankcopy_len\n",idprefix);
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ emit(f,"\tjsr\t%s__bankcopy\n",idprefix);
+ yval=NOVAL;
+}
+
+static void load_far(FILE *f,IC *p,obj *o,int t)
+{
+ int pushed=0;
+ if(!(o->flags&DREFOBJ)) ierror(0);
+ o->flags&=~DREFOBJ;
+ t&=NQ;
+ if(zmeqto(sizetab[t],Z0)) return;
+ /*get_acc(f,p,INT);*/
+ if(pushedacc==t3||pushedacc==t4) ierror(0);
+ if(pushedx==t3||pushedx==t4) ierror(0);
+ if(regs[ra]||regs[rax]){
+ if(isacc(q1)||isacc(q2)||!isacc(z)){
+ pushed=1;
+ emit(f,"\tpha\n");
+ if(regs[rax]) emit(f,"\ttxa\n\tpha\n");
+ }
+ }
+ load_reg(f,LAST_PAIR,o,POINTER);
+ if(!indirect(o))
+ do_byte3(f,"ldy",o,CHAR);
+ else{
+ do_byte3(f,"lda",o,CHAR);
+ emit(f,"\ttay\n");
+ }
+ emit(f,"\tldx\t#%d\n",bankvoffset);
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ emit(f,"\tjsr\t%s__bankload%d\n",idprefix,(int)zm2l(sizetab[t]));
+ yval=NOVAL;
+ o->flags=VAR;
+ o->v=&bankv;
+ o->val.vmax=l2zm((long)bankvoffset);
+ bankvoffset+=zm2l(sizetab[t]);
+ if(pushed){
+ if(regs[rax]) emit(f,"\tpla\n\ttax\n");
+ emit(f,"\tpla\n");
+ }
+}
+
+static void load_banked(FILE *f,IC *p,obj *o,int t)
+{
+ int pushed=0,m;
+ if(o->flags&DREFOBJ) t=o->dtyp;
+ t&=NQ;
+ if(zmeqto(sizetab[t],Z0)) return;
+ /*get_acc(f,p,INT);*/
+ if(pushedacc==t3||pushedacc==t4) ierror(0);
+ if(pushedx==t3||pushedx==t4) ierror(0);
+ if(regs[ra]||regs[rax]){
+ if(isacc(q1)||isacc(q2)||!isacc(z)){
+ pushed=1;
+ emit(f,"\tpha\n");
+ if(regs[rax]) emit(f,"\ttxa\n\tpha\n");
+ }
+ }
+ m=o->flags;
+ o->flags&=~DREFOBJ;
+ load_address(f,LAST_PAIR,o,POINTER);
+ o->flags=m;
+ emit(f,"\tldx\t#%d\n",bankvoffset);
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ sety(f,bank(o->v));
+ emit(f,"\tjsr\t%s__bankload%d\n",idprefix,(int)zm2l(sizetab[t]));
+ yval=NOVAL;
+ o->v=&bankv;
+ o->val.vmax=l2zm((long)bankvoffset);
+ bankvoffset+=zm2l(sizetab[t]);
+ if(pushed){
+ if(regs[rax]) emit(f,"\tpla\n\ttax\n");
+ emit(f,"\tpla\n");
+ }
+}
+
+static void preload(FILE *f,IC *p)
+{
+ int r,mra=regs[ra],mrax=regs[rax];
+ int bq1=-1,bq2=-1,bz=-1,sb=-1,zbuf=0;
+
+ if(p->code==GETRETURN&&p->q1.reg==ra&&!regs[ra])
+ regs[ra]=1;
+
+ if(p->code==GETRETURN&&p->q1.reg==rax&&!regs[rax])
+ regs[rax]=1;
+
+ bankvoffset=0;
+
+ if(!NOBANKVARS){
+ if((p->q1.flags&(VAR|VARADR))==VAR) bq1=bank(p->q1.v);
+ if((p->q2.flags&(VAR|VARADR))==VAR) bq2=bank(p->q2.v);
+ if((p->z.flags&(VAR|VARADR))==VAR) bz=bank(p->z.v);
+
+ if((p->q1.flags&(VAR|VARADR))==(VAR|VARADR)){
+ r=bank(p->q1.v);
+ /*if(r>=0&&r!=cbank) ierror(0);*/
+ }
+
+ if((p->code==ASSIGN||p->code==PUSH)&&!zmleq(p->q2.val.vmax,l2zm(4L))){
+ if(p->q1.flags&DREFOBJ) preload_obj(f,p,&p->q1);
+ if(p->z.flags&DREFOBJ) preload_obj(f,p,&p->z);
+ return;
+ }
+
+ if(p->code!=CALL){
+ /* TODO: some optimizations possible */
+ if(bq1>=0&&bq1!=cbank){
+ if(cbank<0&&!NOSWITCH)
+ sb=bq1;
+ else
+ load_banked(f,p,&p->q1,q1typ(p));
+ }
+ if(bq2>=0&&bq2!=cbank){
+ if((bq2==sb||(cbank<0&&sb<0))&&!NOSWITCH)
+ sb=bq2;
+ else
+ load_banked(f,p,&p->q2,q2typ(p));
+ }
+ if(bz>=0&&bz!=cbank&&(p->z.flags&DREFOBJ)){
+ if((bz==sb||(cbank<0&&sb<0))||!NOSWITCH)
+ sb=bz;
+ else
+ load_banked(f,p,&p->z,ztyp(p));
+ }
+
+ if(sb>=0){
+ if(NOSWITCH) ierror(0);
+ sety(f,sb);
+ emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+ yval=NOVAL;
+ }
+ }
+ }
+
+ if((p->q1.flags&DREFOBJ)&&ISFPOINTER(p->q1.dtyp)&&p->code!=CALL) load_far(f,p,&p->q1,q1typ(p));
+ if((p->q2.flags&DREFOBJ)&&ISFPOINTER(p->q2.dtyp)) load_far(f,p,&p->q2,q2typ(p));
+
+ if(isacc(q2)){
+ static obj o;
+ int t=q2typ(p);
+ r=get_reg(f,p,t);
+ o.flags=REG;
+ o.reg=r;
+ store_acc(f,&o,t);
+ p->q2.reg=r;
+ }
+
+ if(p->code!=ADDRESS){
+ preload_obj(f,p,&p->q1);
+ if((p->q1.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+ (p->q2.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+ p->q1.v==p->q2.v){
+ p->q2.flags|=REG;
+ p->q2.reg=p->q1.reg;
+ }
+ if((p->q1.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+ (p->z.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+ p->q1.v==p->z.v){
+ p->z.flags|=REG;
+ p->z.reg=p->q1.reg;
+ }
+ }
+
+ preload_obj(f,p,&p->q2);
+ if((p->q2.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR|REG)&&
+ (p->z.flags&(DREFOBJ|VAR|REG))==(DREFOBJ|VAR)&&
+ p->q2.v==p->z.v){
+ p->z.flags|=REG;
+ p->z.reg=p->q1.reg;
+ }
+
+
+ if((p->z.flags&DREFOBJ)&&ISFPOINTER(p->z.dtyp)) zbuf=1;
+ if((p->z.flags&(VAR|DREFOBJ))==VAR){
+ bz=bank(p->z.v);
+ if(bz>=0&&bz!=cbank) zbuf=1;
+ }
+
+ if(zbuf&&!NOBANKVARS){
+ zstore=p->z;
+ p->z.flags=VAR;
+ p->z.v=&bankv;
+ p->z.val.vmax=l2zm((long)bankvoffset);
+ zstoreflag=1;
+ /*bankvoffset+=zm2l(sizetab[p->typf&NQ]);*/
+ }else{
+ preload_obj(f,p,&p->z);
+
+ if(isreg(z)){
+ r=0;
+ if(p->q1.am&&p->q1.am->base==p->z.reg){
+ r=get_reg(f,p,POINTER);
+ cmp_get_acc(f,p,0);
+ if(!reg_pair(p->q1.am->base,&rp)) ierror(0);
+ if(!reg_pair(r,&rp2)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+ p->q1.am->base=p->q1.reg=r;
+ }else if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q1.reg==p->z.reg){
+ r=get_reg(f,p,POINTER);
+ cmp_get_acc(f,p,0);
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ if(!reg_pair(r,&rp2)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+ p->q1.reg=r;
+ }
+ if(p->q2.am&&p->q2.am->base==p->z.reg){
+ if(r==0){
+ r=get_reg(f,p,POINTER);
+ cmp_get_acc(f,p,0);
+ if(!reg_pair(p->q2.am->base,&rp)) ierror(0);
+ if(!reg_pair(r,&rp2)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+ }
+ p->q2.am->base=p->q2.reg=r;
+ }else if((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg==p->z.reg){
+ if(r==0){
+ r=get_reg(f,p,POINTER);
+ cmp_get_acc(f,p,0);
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ if(!reg_pair(r,&rp2)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+ }
+ p->q2.reg=r;
+ }
+ }
+ if(isacc(z)){
+ if(isacc(q2)){
+ if(p->q2.reg==rax){
+ r=get_reg(f,p,INT);
+ if(!reg_pair(r,&rp)) ierror(0);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tstx\t%s\n",mregnames[rp.r2]);
+ }else{
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ }
+ p->q2.reg=r;
+ if(isacc(q1))
+ p->q1.reg=r;
+ }
+ }
+ }
+
+ reload_acc(f);
+
+ regs[ra]=mra;
+ regs[rax]=mrax;
+}
+
+
+/* compare if two objects are the same */
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+ if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
+ return 1;
+ if(o1->flags==o2->flags&&o1->am==o2->am){
+ if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+ if(!(o1->flags®)||o1->reg==o2->reg){
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+ ierror(0);
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+ if(p->am){
+ if(p->am->flags==IMM_IND)
+ emit(f,"(%s),y ;am(%ld)",mregnames[p->am->base],p->am->offset);
+ else if(p->am->flags==GPR_IND)
+ emit(f,"(%s),y ;am(%s)",mregnames[p->am->base],mregnames[p->am->idx]);
+ else if(p->am->flags==ABS_IND){
+ emit(f,"%ld",p->am->offset);
+ if(p->am->v){
+ Var *v=p->am->v;
+ if(v->storage_class==EXTERN)
+ emit(f,"+%s%s",idprefix,v->identifier);
+ else
+ emit(f,"+%s%ld",labprefix,zm2l(v->offset));
+ }
+ emit(f,",y ;am(%s)",mregnames[p->am->idx]);
+ }else
+ ierror(0);
+ return;
+ }
+ if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if(p->flags&DREFOBJ) emit(f,"(");
+ if(p->flags®){
+ emit(f,"%s",mregnames[p->reg]);
+ }else if(p->flags&VAR) {
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+ emit(f,"(%s),y",mregnames[fp]);
+ else{
+ if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,MAXINT);emit(f,"+");}
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ }
+ }
+ if(p->flags&KONST){
+ if(/*ieee&&((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)*/ISFLOAT(t))
+ emit(f,"%s%d",labprefix,addfpconst(p,t));
+ else
+ emitval(f,&p->val,t&NU);
+ }
+ if(p->flags&DREFOBJ) emit(f,"),y");
+}
+
+/* Test if there is a sequence of FREEREGs containing FREEREG reg.
+ Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+ while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+ if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+ p=p->next;
+ }
+ return 0;
+}
+
+char amode_buff[8192];
+char *render_amode(struct AddressingMode *am)
+{
+ return "(amode: not implemented)";
+}
+
+char val_buff[8192];
+char *render_val(union atyps val)
+{
+ snprintf(val_buff,8192,"(val: %02x...)",
+ val.vuchar);
+ return val_buff;
+}
+
+char var_buff[8192];
+char *render_var(struct Var *v)
+{
+ if (!v) return "<null>";
+ snprintf(var_buff,8192,"(var id=%s)",v->identifier);
+ return var_buff;
+}
+
+char obj_buff[8192];
+char *render_obj(struct obj o)
+{
+ // XXX Calling render_var() can result in segfaults
+ snprintf(obj_buff,8192,"(flags=%d, reg=%d, dtype=%d, var=%s, amode=%s, val=%s)",
+ o.flags,o.reg,o.dtyp,"render_var(o.v)",render_amode(o.am),render_val(o.val));
+ return obj_buff;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+ int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+ fprintf(stderr,"peephole() called.\n");
+
+ /*
+ XXX PGS Things to consider adding here:
+ 1. Removal of dead loads when we know a register already has loaded the target we want.
+ 2. Removal of dead stores to local stack variables that never get read before returning from a function?
+ 3. Removal of SP decrement and increment, when no use of local stack is made.
+ 4. Promoting stack variables to global variables where it saves time and/or space?
+ 5. Using Z as a temporary scratch register for local variables, where it doesn't upset
+ other things?
+ */
+
+
+ for(;p;p=p->next){
+ fprintf(stderr," Instruction @ %p : ",p);
+ fprintf(stderr,"code=%d, ",p->code);
+ fprintf(stderr,"\n q1=%s, ",render_obj(p->q1));
+ fprintf(stderr,"\n q2=%s, ",render_obj(p->q2));
+ fprintf(stderr,"\n z=%s, ",render_obj(p->z));
+ fprintf(stderr,"\n");
+
+ c=p->code;
+ if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+ if(c==LABEL) exit_label=p->typf;
+
+ /* Try const(reg) */
+ if((c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&!ISFPOINTER(p->typf2)){
+ int base;zmax of;struct obj *o;
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ if(zmleq(Z0,of)&&zmleq(of,l2zm(255L))){
+ r=p->z.reg;
+ if(isreg(q1)&&isptr(p->q1.reg)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ int t,mc;
+ if((c2==ASSIGN|c2==PUSH)&&(p2->typf&NQ)==CHAR&&!zmeqto(p2->q2.val.vmax,Z1))
+ mc=1;
+ else
+ mc=0;
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||mc) break;
+ t=q1typ(p2)&NQ;
+ if(t>POINTER||ISFLOAT(t)) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||mc) break;
+ t=q2typ(p2)&NQ;
+ if(t>POINTER||ISFLOAT(t)) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||mc) break;
+ t=ztyp(p2)&NQ;
+ if(t>POINTER||ISFLOAT(t)) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else{
+ m=p2->z.reg;
+ if(o==&p->q1||o==&p->q2) break;
+ }
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ am->base=base;
+ am->offset=(int)zm2l(of);
+ if(isreg(q1)&&isptr(p->q1.reg)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+ /* Try reg,reg */
+ if(c==ADDI2P&&(p->typf&NU)==(UNSIGNED|CHAR)&&!ISFPOINTER(p->typf2)&&isreg(q2)&&p->q2.reg!=ra&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+ int base,idx,ind;struct obj *o;
+ r=p->z.reg;idx=p->q2.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ if((p->q1.flags&VARADR)||(p->q1.flags&(KONST|DREFOBJ))==KONST)
+ ind=0;
+ else
+ ind=1;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||(ind&&(q1typ(p2)&NQ)!=CHAR)) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||(ind&&(q2typ(p2)&NQ)!=CHAR)) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||(ind&&(ztyp(p2)&NQ)!=CHAR)) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->idx=idx;
+ if(ind){
+ am->flags=GPR_IND;
+ am->base=base;
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }else{
+ am->flags=ABS_IND;
+ am->base=0;
+ eval_const(&p->q1.val,MAXINT);
+ am->offset=zm2l(vmax);
+ if(p->q1.flags&VARADR)
+ am->v=p->q1.v;
+ else
+ am->v=0;
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+}
+
+static void pr(FILE *f,struct IC *p)
+{
+ int r;
+
+ if(zstoreflag){
+ int off;
+ if(p->z.flags!=VAR||p->z.v!=&bankv) ierror(0);
+ off=(int)zm2l(p->z.val.vmax);
+ p->z=zstore;
+ get_acc(f,p,INT);
+ if(zstore.flags&DREFOBJ){
+ if(!ISFPOINTER(zstore.dtyp)) ierror(0);
+ zstore.flags&=~DREFOBJ;
+ load_reg(f,LAST_PAIR,&zstore,POINTER);
+ if(indirect(&zstore)){
+ do_byte3(f,"lda",&zstore,FPOINTER);
+ emit(f,"\ttay\n");
+ }else
+ do_byte3(f,"ldy",&zstore,FPOINTER);
+ yval=NOVAL;
+ }else{
+ load_address(f,LAST_PAIR,&zstore,p->typf);
+ r=bank(zstore.v);
+ sety(f,r>=0?r:bankcnum);
+ }
+ emit(f,"\tldx\t#%d\n",off);
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ emit(f,"\tjsr\t%s__bankstore%d\n",idprefix,(int)zm2l(sizetab[p->typf&NQ]));
+ yval=NOVAL;
+ zstoreflag=0;
+ }
+
+ for(r=1;r<=MAXR;r++){
+ if(regs[r]&8)
+ regs[r]&=~8;
+ }
+ for(r=FIRST_GPR;r<=LAST_GPR;r++){
+ int ta=0;
+ if(regs[r]&2){
+ if(regs[ra]&&!pushedacc){
+ emit(f,"\ttay\n");
+ yval=NOVAL;
+ ta=1;
+ }
+ emit(f,"\tpla\n");
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ regs[r]&=~2;
+ }
+ if(ta)
+ emit(f,"\ttya\n");
+ }
+ if(pushedx){
+ emit(f,"\tldx\t%s\n",mregnames[pushedx]);
+ pushedx=0;
+ }
+
+ reload_acc_opt(f,p->next);
+}
+
+struct cmplist {struct cmplist *next;int from,to,mode;} *first_cmplist;
+
+static void add_cmplist(int from, int to, int mode)
+{
+ struct cmplist *new;
+ new=mymalloc(sizeof(*new));
+ new->next=first_cmplist;
+ new->from=from;
+ new->to=to;
+ new->mode=mode;
+ first_cmplist=new;
+}
+
+static void incsp(FILE *f,long of)
+{
+ if(of==0) return;
+ if(of==1||of==-1){
+ static obj o;
+ o.flags=REG;
+ o.reg=sp;
+ if(of==1)
+ incmem(f,&o,INT,ADD,1);
+ else
+ incmem(f,&o,INT,SUB,1);
+ }else if(of==256){
+ emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+ }else if(of==-256){
+ emit(f,"\tdec\t%s+1\n",mregnames[sp]);
+ }else{
+ long abs;
+ if(of>0){
+ abs=of;
+ emit(f,"\tclc\n");
+ }else{
+ abs=-of;
+ emit(f,"\tsec\n");
+ }
+ if(abs&255){
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ if(of>0){
+ emit(f,"\tadc\t#%ld\n",abs&255);
+ }else{
+ emit(f,"\tsbc\t#%ld\n",abs&255);
+ }
+ emit(f,"\tsta\t%s\n",mregnames[sp]);
+ }
+ if((abs&0xff00)==0){
+ if(of>0){
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+ emit(f,"%s%d:\n",labprefix,label);
+ }else{
+ emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+ emit(f,"\tdec\t%s+1\n",mregnames[sp]);
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }else{
+ emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+ if(of>0)
+ emit(f,"\tadc\t#%ld\n",(abs>>8)&255);
+ else
+ emit(f,"\tsbc\t#%ld\n",(abs>>8)&255);
+ emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+ }
+ }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+ int i,r,of;
+ rsavesize=0;
+ libsave=1;
+
+ if(!optsize||(v->tattr&NOCOMPRESS)) emit(f,";vcprmin=10000\n");
+ if(vlas) emit(f,"___fo\tset\t%ld\n",(long)argsize);
+ r=0;
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&®scratch[i]&&!regsa[i])){
+ if(i!=LAST_GPR-VOL_GPRS+1&&r==0) libsave=0;
+ rsavesize++;
+ r=1;
+ }else{
+ if(i==LAST_GPR-VOL_GPRS+1) libsave=0;
+ r=0;
+ }
+ }
+ rscnt=rsavesize;
+ if(rscnt&&!SOFTSTACK){
+ if(optspeed||rscnt<2)
+ rsavesize=0;
+ else if(!optsize&&rscnt<=5)
+ rsavesize=0;
+ }
+
+ if(!special_section(f,v)){emit(f,codename);ebank(f,bank(v));if(f) section=CODE;}
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\tglobal\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+
+ offset=localsize+argsize+rsavesize;
+
+ if(in_isr){
+ emit(f,"\tpha\n");
+ emit(f,"\tphx\n");
+ emit(f,"\tphy\n");
+ emit(f,"\tphz\n");
+ if(offset||function_calls){
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ emit(f,"\tpha\n");
+ emit(f,"\tlda\t%s+1\n",mregnames[sp]);
+ emit(f,"\tpha\n");
+ emit(f,"\tlda\t#<(___isrstack-%ld)\n",offset);
+ emit(f,"\tsta\t%s\n",mregnames[sp]);
+ emit(f,"\tlda\t#>(___isrstack-%ld)\n",offset);
+ emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+ }
+ }
+
+ if(MAINARGS&&v->storage_class==EXTERN&&!strcmp(v->identifier,"main")&&v->vtyp->exact->count>1)
+ emit(f,"\tjsr\tinitmainargs\n");
+
+ yval=NOVAL;
+ of=argsize+localsize;
+
+ if(rsavesize>0&&of+rsavesize>255){
+ offset-=rsavesize;
+ incsp(f,-rsavesize);
+ of=0;
+ }else{
+ incsp(f,-offset);
+ offset=0;
+ }
+
+
+ if(!libsave||rscnt!=rsavesize||optspeed||rscnt<=1||(rscnt<=3&&(!optsize)))
+ libsave=0;
+
+ if(libsave){
+ sety(f,of+rsavesize-1);
+ emit(f,"\tjsr\t%s__rsave%ld\n",idprefix,rscnt);
+ yval=of;
+ }else{
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&®scratch[i]&&!regsa[i])){
+ if(rscnt!=rsavesize){
+ emit(f,"\tlda\t%s\n",mregnames[i]);
+ emit(f,"\tpha\n");
+ }else{
+ sety(f,of++);
+ emit(f,"\tlda\t%s\n",mregnames[i]);
+ emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+ }
+ }
+ }
+ }
+
+
+
+ incsp(f,-offset);
+
+ if(vlas){
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ emit(f,"\tsta\t%s\n",mregnames[fp]);
+ emit(f,"\tlda\t%s\n",mregnames[sp2]);
+ emit(f,"\tsta\t%s\n",mregnames[fp2]);
+ }
+}
+
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+ int i,of,ar;
+ struct cmplist *p;
+ offset=localsize+argsize+rsavesize;
+ of=argsize+localsize;
+
+ i=freturn(v->vtyp->next);
+ if(i==ra||i==rax) ar=1; else ar=0;
+
+ if(rscnt!=rsavesize){
+ if(ar&&!pushedacc){
+ pushedacc=t4;
+ emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+ }
+ for(i=LAST_GPR;i>=FIRST_GPR;i--){
+ if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&®scratch[i]&&!regsa[i])){
+ emit(f,"\tpla\n");
+ emit(f,"\tsta\t%s\n",mregnames[i]);
+ }
+ }
+ }
+ if(rsavesize>0&&of+rsavesize>255){
+ if(of!=1&&ar&&!pushedacc){
+ pushedacc=t4;
+ emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+ }
+ incsp(f,of);
+ offset-=of;
+ of=0;
+ }
+ if(rsavesize>0){
+ if(ar&&!pushedacc){
+ pushedacc=t4;
+ emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+ }
+ }
+ if(rsavesize){
+ if(libsave){
+ sety(f,of+rsavesize-1);
+ emit(f,"\tjsr\t%s__rload%ld\n",idprefix,rscnt);
+ yval=of;
+ }else{
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ if((regused[i]&&(in_isr||!regscratch[i]))||(in_isr&&function_calls&®scratch[i]&&!regsa[i])){
+ sety(f,of++);
+ emit(f,"\tlda\t(%s),y\n",mregnames[sp]);
+ emit(f,"\tsta\t%s\n",mregnames[i]);
+ }
+ }
+ }
+ }
+ if(in_isr){
+ if(offset||function_calls){
+ emit(f,"\tpla\n");
+ emit(f,"\tsta\t%s+1\n",mregnames[sp]);
+ emit(f,"\tpla\n");
+ emit(f,"\tsta\t%s\n",mregnames[sp]);
+ }
+ }else if(offset==2&&!pushedacc){
+ emit(f,"\tinc\t%s\n",mregnames[sp]);
+ emit(f,"\tbeq\t%s%d\n",labprefix,++label);
+ emit(f,"\tinc\t%s\n",mregnames[sp]);
+ emit(f,"\tbeq\t%s%d\n",labprefix,++label);
+ reload_acc(f);
+ emit(f,ret);
+ emit(f,"%s%d:\n",labprefix,label-1);
+ emit(f,"\tinc\t%s\n",mregnames[sp]);
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tinc\t%s+1\n",mregnames[sp]);
+ }else{
+ if(offset!=0&&ar&&!pushedacc){
+ pushedacc=t4;
+ emit(f,"\tsta\t%s\n",mregnames[pushedacc]);
+ }
+ incsp(f,offset);
+ }
+
+ reload_acc(f);
+
+ if(in_isr){
+ emit(f,"\tplz\n");
+ emit(f,"\tply\n");
+ emit(f,"\tplx\n");
+ emit(f,"\tpla\n");
+ }
+ emit(f,ret);
+
+ for(p=first_cmplist;p;){
+ struct cmplist *m;
+ emit(f,"%s%d:\n",labprefix,p->from);
+ if(p->mode==JMPIND){
+ /* indirect call */
+ emit(f,"\tjmp\t(%s)\n",mregnames[p->to]);
+ }else{
+ pushedacc=p->mode;
+ reload_acc(f);
+ emit(f,"\tjmp\t%s%d\n",labprefix,p->to);
+ }
+ m=p;
+ p=p->next;
+ free(m);
+ }
+ first_cmplist=0;
+ pushedacc=0;
+}
+
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+int init_cg(void)
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(1L);
+ char_bit=l2zm(8L);
+ stackalign=l2zm(1);
+
+ if(IEEE){
+ ieee=1;
+ msizetab[DOUBLE]=msizetab[LDOUBLE]=l2zm(8L);
+ }
+
+
+ mregnames[0]=regnames[0]="noreg";
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"r%d",i-FIRST_GPR);
+ mregnames[i]=regnames[i];
+ regsize[i]=l2zm(1L);
+ regtype[i]=&ctyp;
+ }
+ for(i=FIRST_PAIR;i<=LAST_PAIR;i++){
+ int sr=(i-FIRST_PAIR)*2+FIRST_GPR;
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"%s/%s",mregnames[sr],mregnames[sr+1]);
+ mregnames[i]=regnames[sr];
+ regsize[i]=l2zm(2L);
+ regtype[i]=&ityp;
+ }
+ for(i=FIRST_BIG;i<=LAST_BIG;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"btmp%d",i-FIRST_BIG);
+ mregnames[i]=regnames[i];
+ regsize[i]=msizetab[FLOAT];
+ regtype[i]=&ftyp;
+ regsa[i]=0;
+ regscratch[i]=1;
+ }
+ for(i=FIRST_BIGP;i<=LAST_BIGP;i++){
+ int sr=(i-FIRST_BIGP)*2+FIRST_BIG;
+ regnames[i]=mymalloc(20);
+ sprintf(regnames[i],"%s/%s",mregnames[sr],mregnames[sr+1]);
+ mregnames[i]=regnames[sr];
+ regsize[i]=msizetab[LLONG];
+ regtype[i]=&lltyp;
+ regsa[i]=0;
+ regscratch[i]=1;
+ }
+
+ mregnames[ra] = regnames[ra] = "a";
+ mregnames[rx] = regnames[rx] = "x";
+ mregnames[ry] = regnames[ry] = "y";
+ mregnames[rz] = regnames[rz] = "z";
+ regsize[ra]=regsize[rx]=regsize[ry]=l2zm(1L);
+ regtype[ra]=regtype[rx]=regtype[ry]=&ctyp;
+ mregnames[sp]=regnames[sp] = "sp";
+ mregnames[sp1]=regnames[sp1] = "sp";
+ mregnames[sp2]=regnames[sp2] = "sp+1";
+
+ mregnames[rax]=regnames[rax] = "ax";
+ regsize[rax]=regsize[sp]=l2zm(2L);
+ regtype[rax]=regtype[sp]=&ityp;
+
+ reg_prio[ra]=reg_prio[rax]=100;
+ reg_prio[rx]=50;
+
+ mregnames[raxyz]=regnames[raxyz] = "axyz";
+ regsize[raxyz]=l2zm(3L);
+ regtype[raxyz]=&lltyp;
+
+ /* Use multiple ccs. */
+ multiple_ccs=0;
+
+ short_push=1;
+
+ static_cse=0;
+
+ dref_cse=1;
+
+ /*prefer_statics=1; TODO */
+
+
+ if(optsize){
+ clist_copy_stack=2;
+ clist_copy_pointer=2;
+ clist_copy_static=2;
+ }else if(optspeed){
+ clist_copy_stack=64;
+ clist_copy_pointer=64;
+ clist_copy_static=64;
+ }else{
+ clist_copy_stack=8;
+ clist_copy_pointer=8;
+ clist_copy_static=8;
+ }
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[INT]=t_min(SHORT);
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[LONG]=ul2zum(2147483647UL);
+ t_max[INT]=t_max(SHORT);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[LONG]=ul2zum(4294967295UL);
+ tu_max[INT]=t_max(UNSIGNED|SHORT);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ /* This is not optimal but simple. */
+ regsa[raxyz]=regsa[rz]=regsa[ry]=regsa[sp]=regsa[sp1]=regsa[sp2]=REGSA_NEVER;
+ regsa[t1]=regsa[t2]=regsa[t3]=regsa[t4]=REGSA_NEVER;
+ regscratch[ra]=regscratch[rx]=regscratch[rax]=1;
+ if(!GLOBACC)
+ regsa[ra]=regsa[rx]=regsa[rax]=REGSA_TEMPS;
+ regscratch[sp]=regscratch[sp1]=regscratch[sp2]=regscratch[ry]=regscratch[rz]=0;
+ regscratch[t1]=regscratch[t2]=regscratch[t3]=regscratch[t4]=1;
+
+ for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++){
+ regscratch[i]=1;
+ if(i&1)
+ regscratch[FIRST_PAIR+(i-FIRST_GPR)/2]=1;
+ }
+
+ target_macros=marray;
+
+ declare_builtin("__mulint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__muluint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__divuint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__divint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__moduint16",UNSIGNED|INT,UNSIGNED|INT,FIRST_PAIR,UNSIGNED|INT,FIRST_PAIR+1,1,0);
+ declare_builtin("__modint16",INT,INT,FIRST_PAIR,INT,FIRST_PAIR+1,1,0);
+
+ declare_builtin("__mulint32",LONG,LONG,FIRST_BIG+1,LONG,FIRST_BIG+2,1,0);
+ declare_builtin("__muluint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG+1,UNSIGNED|LONG,FIRST_BIG+2,1,0);
+ declare_builtin("__divint32",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+ declare_builtin("__divuint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+ declare_builtin("__modint32",LONG,LONG,FIRST_BIG,LONG,FIRST_BIG+1,1,0);
+ declare_builtin("__moduint32",UNSIGNED|LONG,UNSIGNED|LONG,FIRST_BIG,UNSIGNED|LONG,FIRST_BIG+1,1,0);
+
+ declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+ declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+ declare_builtin("__divint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__modint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__lsrint64",LLONG,LLONG,0,INT,0,1,0);
+ declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+ declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+
+ declare_builtin("__sint32toflt32",FLOAT,LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__uint32toflt32",FLOAT,UNSIGNED|LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__flt32tosint32",LONG,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__flt32touint32",UNSIGNED|LONG,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__sint16toflt32",FLOAT,INT,FIRST_PAIR,0,0,1,0);
+ declare_builtin("__uint16toflt32",FLOAT,UNSIGNED|INT,FIRST_PAIR,0,0,1,0);
+ declare_builtin("__flt32tosint16",INT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__flt32touint16",UNSIGNED|INT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+
+ declare_builtin("__sint32toflt64",DOUBLE,LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__uint32toflt64",DOUBLE,UNSIGNED|LONG,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__flt64tosint32",LONG,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+ declare_builtin("__flt64touint32",UNSIGNED|LONG,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+ declare_builtin("__sint16toflt64",DOUBLE,INT,FIRST_PAIR,0,0,1,0);
+ declare_builtin("__uint16toflt64",DOUBLE,UNSIGNED|INT,FIRST_PAIR,0,0,1,0);
+ declare_builtin("__flt64tosint16",INT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+ declare_builtin("__flt64touint16",UNSIGNED|INT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+
+ declare_builtin("__flt64toflt32",FLOAT,DOUBLE,OLDFP?0:FIRST_BIGP,0,0,1,0);
+ declare_builtin("__flt32toflt64",DOUBLE,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+
+ declare_builtin("__addflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+ declare_builtin("__subflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+ declare_builtin("__mulflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+ declare_builtin("__divflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+ declare_builtin("__negflt32",FLOAT,FLOAT,OLDFP?0:FIRST_BIG,0,0,1,0);
+ declare_builtin("__cmpsflt32",CHAR,FLOAT,OLDFP?0:FIRST_BIG+1,FLOAT,OLDFP?0:FIRST_BIG,1,0);
+
+#if 0
+ for(i=1;i<MAXR;i++){
+ printf("%02d %s scratch=%d ",i,regnames[i],regscratch[i]);
+ if(reg_pair(i,&rp))
+ printf("pair(%s,%s)",regnames[rp.r1],regnames[rp.r2]);
+ printf("\n");
+ }
+#endif
+
+ if(NOPEEP) nopeep=1;
+ if(CBMASCII) cbmascii=1;
+ if(ATASCII) atascii=1;
+
+
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+
+ bankv.storage_class=EXTERN;
+ bankv.identifier="__bankv";
+ bankv.vtyp=new_typ();
+ bankv.vtyp->flags=CHAR;
+
+ bankcnum=COMMONBANK;
+
+ return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+/* A pointer MUST be returned in a register. The code-generator */
+/* has to simulate a pseudo register if necessary. */
+{
+ int typ=t->flags&NQ;
+ if(ISSTRUCT(typ)||ISUNION(typ)||typ==VOID)
+ return 0;
+ if(OLDFP&&ISFLOAT(typ)) return FIRST_GPR;
+ if(typ==LONG||typ==FLOAT||ISFPOINTER(typ)||(!ieee&&(typ==DOUBLE||typ==LDOUBLE)))
+ return FIRST_BIG;
+ if(typ==LLONG||(ieee&&(typ==DOUBLE||typ==LDOUBLE)))
+ return FIRST_BIGP;
+ if(zmleq(szof(t),l2zm(1L)))
+ return ra;
+ if(zmleq(szof(t),l2zm(2L)))
+ return rax;
+ else
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ if(r>=FIRST_PAIR&&r<=LAST_PAIR){
+ p->r1=(r-FIRST_PAIR)*2+FIRST_GPR;
+ p->r2=p->r1+1;
+ return 1;
+ }else if(r>=FIRST_BIGP&&r<=LAST_BIGP){
+ p->r1=(r-FIRST_BIGP)*2+FIRST_BIG;
+ p->r2=p->r1+1;
+ return 1;
+ }else if(r==rax){
+ p->r1=ra;
+ p->r2=rx;
+ return 1;
+ }else if(r==raxyz) {
+ // TODO: PGS: How do we declare a reg pair that is made of 4 regs, not 2?
+ p->r1=ra;
+ p->r2=rx;
+ return 1;
+ }else if(r==sp){
+ p->r1=sp1;
+ p->r2=sp2;
+ return 1;
+ }
+ return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+ register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+ int c=p->code;
+ /*TODO: adapt this */
+ if(o->flags&VKONST){
+ return 0;
+ if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
+ return 4;
+ else
+ return 2;
+ }
+ if(o->flags&DREFOBJ){
+ if(isptr(r))
+ return 4;
+ if(r==rax)
+ return INT_MIN;
+ }
+ if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 6;
+ if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 6;
+ if(r==ra)
+ return 5;
+ if(r==rx)
+ return 4;
+ if(r==rax)
+ return 2;
+ return 2;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(r==0)
+ return 0;
+ if(r==rax&&NORAX)
+ return 0;
+ t&=NQ;
+ if(ISCHAR(t))
+ if(r==ra/*||r==rx*/||(r>=FIRST_GPR&&r<=LAST_GPR))
+ return 1;
+ if(ISSHORT(t)){
+ if(r==rax){
+ if(t==POINTER&&mode<0)
+ return 1;
+ if(t!=POINTER)
+ return 1;
+ }
+ if(r>=FIRST_PAIR&&r<=LAST_PAIR)
+ return 1;
+ }
+ if(r>=FIRST_BIG&&r<=LAST_BIG){
+ if(t==LONG||t==FLOAT||((t==DOUBLE||t==LDOUBLE)&&!ieee))
+ return 1;
+ if(t==FPOINTER)
+ return 1;
+ }
+ if(r>=FIRST_BIGP&&r<=LAST_BIGP){
+ if(t==LLONG||((t==DOUBLE||t==LDOUBLE)&&ieee))
+ return 1;
+ }
+ return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* On the PowerPC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op=o&NQ,tp=t&NQ;
+
+ if(op==tp) return 0;
+ if(ISCHAR(op)&&ISCHAR(tp)) return 0;
+ if(ISSHORT(op)&&ISSHORT(tp)) return 0;
+ if(!ieee&&ISFLOAT(op)&&ISFLOAT(tp)) return 0;
+ if(op==DOUBLE&&tp==LDOUBLE) return 0;
+ if(op==LDOUBLE&&tp==DOUBLE) return 0;
+
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ if(STDSYNTAX)
+ emit(f,"\tspace\t%ld\n",zm2l(size));
+ else
+ emit(f,"\treserve\t%ld\n",zm2l(size));
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ if(zm2l(align)>1) emit(f,"\talign 1\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag,b=bank(v);char *sec;
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(v->tattr&ZPAGE)
+ emit(f,"\tzpage\t%s%ld\n",labprefix,zm2l(v->offset));
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))){emit(f,dataname);ebank(f,b);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)){emit(f,rodataname);ebank(f,b);if(f) section=RODATA;}
+ if(!v->clist){emit(f,bssname);ebank(f,b);if(f) section=BSS;}
+ }
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ newobj=1;
+ }
+ if(v->storage_class==EXTERN){
+ emit(f,"\tglobal\t%s%s\n",idprefix,v->identifier);
+ if(v->tattr&ZPAGE)
+ emit(f,"\tzpage\t%s%s\n",idprefix,v->identifier);
+ if(v->flags&(DEFINED|TENTATIVE)){
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))){emit(f,dataname);ebank(f,b);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)){emit(f,rodataname);ebank(f,b);if(f) section=RODATA;}
+ if(!v->clist){emit(f,bssname);ebank(f,b);if(f) section=BSS;}
+ }
+
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ if(ISCHAR(t))
+ emit(f,"\tbyte\t");
+ else
+ emit(f,"\tword\t");
+ if(!p->tree){
+ if(ISLONG(t)||ISFLOAT(t)){
+ if(ieee&&ISFLOAT(t)){
+ emit_ieee(f,&p->val,t&NQ);
+ }else{
+ eval_const(&p->val,t&NU);
+ if(ISFLOAT(t)) cnv_fp();
+ gval.vmax=zmand(vmax,l2zm(0xffffL));
+ emitval(f,&gval,MAXINT);
+ emit(f,",");
+ gval.vmax=zmand(zmrshift(vmax,l2zm(16L)),l2zm(0xffffL));
+ emitval(f,&gval,MAXINT);
+ }
+ }else{
+ if(ISFPOINTER(t)){
+ eval_const(&p->val,t&NU);
+ emit(f,"%ld\n",(long)zm2l(vmax)&0xffff);
+ emit(f,"\tbyte\t%d\n",(int)((zm2l(vmax)>>16)&0xff));
+ }else
+ emitval(f,&p->val,t&NU);
+ }
+ }else{
+ emit_obj(f,&p->tree->o,t&NU);
+ if(ISFPOINTER(t)){
+ int b;
+ if((p->tree->o.flags&(VAR|VARADR))!=(VAR|VARADR)) ierror(0);
+ b=bank(p->tree->o.v);
+ emit(f,"\n\tbyte\t%d",b>=0?b:bankcnum);
+ }
+ }
+ emit(f,"\n");newobj=0;
+}
+
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/* The main code-generation. */
+{
+ int c,t,i;
+ struct IC *mi;
+ FILE *rf=f;
+ static char *dbgfile;
+ static int dbgline;
+
+ if(vlas){
+ fp=FPVLA_REG;
+ if(!reg_pair(fp,&rp)) ierror(0);
+ fp1=rp.r1;
+ fp2=rp.r2;
+ regused[fp]=regused[fp1]=regused[fp2]=1;
+ }else{
+ fp=sp;
+ fp1=sp1;
+ fp2=sp2;
+ }
+ argsize=0;
+ localsize=offset;
+ if(DEBUG&1) printf("gen_code()\n");
+
+ cbank=bank(v);
+
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_REGS;
+
+ for(pass=0;pass<2;pass++){
+
+ if(DEBUG&1) printf("pass %d\n",pass);
+
+ if(pass==0){
+ f=0;
+ mi=clone_ic(p);
+ }else
+ f=rf;
+
+ for(c=1;c<=MAXR;c++) regs[c]=0; /*regsa[c];*/
+ maxpushed=0;
+
+ /*FIXME*/
+ if(v->tattr&INTERRUPT){
+ ret="\trti\n";
+ in_isr=1;
+ }else{
+ ret="\trts\n";
+ in_isr=0;
+ }
+
+ if(!nopeep) peephole(pass==0?p:mi);
+
+ function_top(f,v,localsize);
+
+ pushed=0;
+
+ yval=NOVAL;
+
+ dbgfile=0;
+ dbgline=0;
+
+ for(p=pass==0?p:mi;p;pr(f,p),p=p->next){
+
+
+
+ if(DEBUG&1) pric2(stdout,p);
+
+ if(debug_info){
+ if(p->file&&p->line){
+ if(p->file!=dbgfile||p->line!=dbgline){
+ dbgfile=p->file;
+ dbgline=p->line;
+ emit(f,"; %d \"%s\"\n",dbgline,dbgfile);
+ }
+ }
+ }
+
+ c=p->code;t=p->typf;
+
+ if(c==NOP) {p->z.flags=0;continue;}
+ if(c==ALLOCREG){
+ regs[p->q1.reg]=1;
+ if(reg_pair(p->q1.reg,&rp)){
+ regs[rp.r1]=1;
+ regs[rp.r2]=1;
+ }
+ continue;
+ }
+ if(c==FREEREG){
+ regs[p->q1.reg]=0;
+ if(reg_pair(p->q1.reg,&rp)){
+ regs[rp.r1]=0;
+ regs[rp.r2]=0;
+ }
+ continue;
+ }
+ if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);yval=NOVAL;continue;}
+ if(c==BRA){
+ yval=NOVAL;
+ if(t==exit_label&&localsize+argsize+rsavesize+rscnt==0)
+ emit(f,ret);
+ else
+ emit(f,"\tjmp\t%s%d\n",labprefix,t);
+ continue;
+ }
+ if(c>=BEQ&&c<BRA){
+ yval=NOVAL;
+ continue;
+ }
+
+ if(c==MOVETOREG){
+ p->code=c=ASSIGN;
+ p->typf=t=regtype[p->z.reg]->flags;
+ p->q2.val.vmax=sizetab[regtype[p->z.reg]->flags];
+ }
+ if(c==MOVEFROMREG){
+ p->code=c=ASSIGN;
+ p->typf=t=regtype[p->q1.reg]->flags;
+ p->q2.val.vmax=sizetab[regtype[p->q1.reg]->flags];
+ }
+ if(c==CONVERT&&ISCHAR(t)&&ISCHAR(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[CHAR];
+ }
+ if(c==CONVERT&&msizetab[t&NQ]==3&&msizetab[p->typf2&NQ]==3){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[SHORT];
+ }
+ if(c==CONVERT&&ISSHORT(t)&&ISSHORT(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[SHORT];
+ }
+ if(c==CONVERT&&ISLONG(t)&&ISLONG(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[LONG];
+ }
+ if(c==CONVERT&&ISLLONG(t)&&ISLLONG(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[LLONG];
+ }
+ if(c==CONVERT&&ISFLOAT(t)&&ISFLOAT(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[t&NQ];
+ }
+
+
+ /* switch commutative operands if suitable */
+ if(c==ADD||c==MULT||c==AND||c==XOR||c==OR||(c==ADDI2P&&ISSHORT(t)&&!ISFPOINTER(p->typf2))){
+ if(compare_objects(&p->q2,&p->z)||isacc(q2)){
+ struct obj tmp;
+ tmp=p->q1;
+ p->q1=p->q2;
+ p->q2=tmp;
+ }
+ }
+
+ if(c==COMPARE&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+ obj tmp;
+ tmp=p->q1;
+ p->q1=p->q2;
+ p->q2=tmp;
+ }
+
+ c=p->code;
+ if(c==SUBPFP) c=SUB;
+ /*if(c==ADDI2P) c=ADD;*/
+ /*if(c==SUBIFP) c=SUB;*/
+
+
+ if(c==MINUS){
+ if(isacc(q1)&&isacc(z)){
+ emit(f,"\tneg\n");
+ if(!ISCHAR(t)){
+ emit(f,"\tpha\n");
+ emit(f,"\ttxa\n");
+ emit(f,"\teor\t#255\n");
+ emit(f,"\tadc\t#0\n");
+ emit(f,"\ttax\n");
+ emit(f,"\tpla\n");
+ }
+ continue;
+ }
+ p->code=c=SUB;
+ p->q2=p->q1;
+ p->q1.flags=KONST;
+ gval.vmax=Z0;
+ eval_const(&gval,MAXINT);
+ insert_const(&p->q1.val,t);
+ }
+
+ preload(f,p);
+
+ if(c==CONVERT){
+ int to=q1typ(p)&NU;
+ t&=NU;
+ if(ISCHAR(t)){
+ get_acc(f,p,CHAR);
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+ continue;
+ }
+ if(ISLONG(to)){
+ if(!isacc(z))
+ get_acc(f,p,CHAR);
+ if(zm2l(sizetab[t&NQ])==3){
+ do_byte3(f,"lda",&p->q1,to);
+ do_byte3(f,"sta",&p->z,t);
+ }
+ if(zm2l(sizetab[t&NQ])>=2){
+ load_hibyte(f,&p->q1,to);
+ store_hibyte(f,&p->z,t);
+ }
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+ continue;
+ }
+ if(ISSHORT(to)){
+ if((t&UNSIGNED)||ISFPOINTER(t))
+ get_acc(f,p,CHAR);
+ else
+ get_acc(f,p,SHORT);
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+ load_hibyte(f,&p->q1,to);
+ store_hibyte(f,&p->z,t);
+ if(ISFPOINTER(t)){
+ int b=-1;
+ if((p->q1.flags&(VARADR|DREFOBJ))==VARADR) b=bank(p->q1.v);
+ emit(f,"\tlda\t#%d\n",b>=0?b:bankcnum);
+ do_byte3(f,"sta",&p->z,t);
+ continue;
+ }
+ if(to&UNSIGNED){
+ emit(f,"\tlda\t#0\n");
+ do_byte3(f,"sta",&p->z,t);
+ do_byte4(f,"sta",&p->z,t);
+ }else{
+ emit(f,"\tldx\t#0\n");
+ emit(f,"\tcmp\t#0\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdex\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(indirect(&p->z)){
+ emit(f,"\ttxa\n");
+ do_byte3(f,"sta",&p->z,t);
+ do_byte4(f,"sta",&p->z,t);
+ }else{
+ do_byte3(f,"stx",&p->z,t);
+ do_byte4(f,"stx",&p->z,t);
+ }
+ }
+ continue;
+ }
+ if(ISCHAR(to)){
+ if(to&UNSIGNED){
+ get_acc(f,p,CHAR);
+ if(ISLONG(t)){
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+ emit(f,"\tlda\t#0\n");
+ store_hibyte(f,&p->z,t);
+ do_byte3(f,"sta",&p->z,t);
+ if(ISLONG(t))
+ do_byte4(f,"sta",&p->z,t);
+ continue;
+ }
+ if(isacc(z))
+ emit(f,"\tldx\t#0\n");
+ else if(isacc(q1)){
+ emit(f,"\tldx\t#0\n");
+ store_acc(f,&p->z,t);
+ continue;
+ }else{
+ emit(f,"\tlda\t#0\n");
+ store_hibyte(f,&p->z,t);
+ }
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+ }else{
+ int l=++label;
+ get_acc(f,p,SHORT);
+ emit(f,"\tldx\t#0\n");
+ if(isreg(q1)&&p->q1.reg==ra)
+ emit(f,"\tcmp\t#0\n");
+ else
+ load_lobyte(f,&p->q1,to);
+ emit(f,"\tbpl\t%s%d\n",labprefix,label);
+ emit(f,"\tdex\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ store_lobyte(f,&p->z,t);
+ if(indirect(&p->z)){
+ emit(f,"\ttxa\n");
+ store_hibyte(f,&p->z,t);
+ if(ISLONG(t)){
+ do_byte3(f,"sta",&p->z,t);
+ do_byte4(f,"sta",&p->z,t);
+ }
+ }else{
+ if(!isreg(z)||p->z.reg!=rax){
+ emit(f,"\tstx\t");
+ emit_hibyte(f,&p->z,t);
+ emit(f,"\n");
+ }
+ if(ISLONG(t)){
+ do_byte3(f,"stx",&p->z,t);
+ do_byte4(f,"stx",&p->z,t);
+ }
+ }
+ }
+ if(ISFPOINTER(t)){
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ do_byte3(f,"sta",&p->z,t);
+ }
+ continue;
+ }
+ if(ISFPOINTER(to)){
+ get_acc(f,p,CHAR);
+ if(zm2l(sizetab[t&NQ])>=3){
+ do_byte3(f,"lda",&p->q1,to);
+ do_byte3(f,"sta",&p->z,t);
+ }
+ if(zm2l(sizetab[t&NQ])>=2){
+ load_hibyte(f,&p->q1,to);
+ store_hibyte(f,&p->z,t);
+ }
+ load_lobyte(f,&p->q1,to);
+ store_lobyte(f,&p->z,t);
+
+ continue;
+ }
+ ierror(0);
+ }
+
+ if(c==KOMPLEMENT){
+ get_acc(f,p,CHAR);
+ if(ISCHAR(t)){
+ load_acc(f,&p->q1,t);
+ emit(f,"\teor\t#-1\n");
+ store_acc(f,&p->z,t);
+ }else{
+ if(isacc(q1))
+ emit(f,"\tpha\n");
+ if(ISLONG(t)){
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\teor\t#-1\n");
+ do_byte4(f,"sta",&p->z,t);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\teor\t#-1\n");
+ do_byte3(f,"sta",&p->z,t);
+ }
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\teor\t#-1\n");
+ store_hibyte(f,&p->z,t);
+ if(isacc(q1))
+ emit(f,"\tpla\n");
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\teor\t#-1\n");
+ store_lobyte(f,&p->z,t);
+ }
+ continue;
+ }
+ if(c==SETRETURN){
+ t&=NQ;
+ if(isreg(q1)&&p->q1.reg==p->z.reg) continue;
+ if(t==LONG||t==LLONG||ISFLOAT(t)||ISFPOINTER(t)){
+ long l=zm2l(p->q2.val.vmax);
+ int zr=p->z.reg;
+ //get_acc(f,p,t);
+ if((optsize||l>4)&&!ISFPOINTER(t)){
+ int ind=indirect(&p->q1);
+ if(ind) load_address(f,LAST_PAIR,&p->q1,t);
+ BSET(regused,t3);
+ BSET(regused,t4);
+ sety(f,l-1);
+ emit(f,"%s%d:\n",labprefix,++label);
+ if(ind)
+ emit(f,"\tlda\t(%s),y\n",mregnames[LAST_PAIR]);
+ else{
+ emit(f,"\tlda\t");
+ if(!ISFLOAT(t)&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+ emit(f,"%s%d",labprefix,addfpconst(&p->q1,t));
+ }else
+ emit_obj(f,&p->q1,t);
+ emit(f,",y\n");
+ }
+ emit(f,"\tsta\t%s,y\n",mregnames[zr]);
+ emit(f,"\tdey\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,label);
+ yval=255;
+ }else{
+ if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ if(p->q1.reg==zr){
+ int r=get_reg(f,p,POINTER);
+ if(r==FIRST_PAIR||r==FIRST_PAIR+1)
+ ierror(0);
+ if(!reg_pair(r,&rp2)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[zr]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tlda\t%s+1\n",mregnames[zr]);
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r2]);
+ p->q1.reg=r;
+ }
+ }
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[zr]);
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s+1\n",mregnames[zr]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s+2\n",mregnames[zr]);
+ if(!ISFPOINTER(t)){
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s+3\n",mregnames[zr]);
+ }
+ /*TODO:regused OLDFP */
+ regused[zr]=1;
+ }
+ continue;
+ }
+ //get_acc(f,p,t);
+ load_acc(f,&p->q1,t);
+ regused[ra]=1;
+ regused[rx]=1;
+ continue;
+ }
+ if(c==GETRETURN){
+ t&=NQ;
+ if(isreg(z)&&p->q1.reg==p->z.reg) continue;
+ if(t==LONG||t==LLONG||ISFLOAT(t)||ISFPOINTER(t)){
+ long l=zm2l(p->q2.val.vmax);
+ int qr=p->q1.reg;
+ if((optsize||l>4)&&!ISFPOINTER(t)){
+ int ind=indirect(&p->z);
+ if(ind) load_address(f,LAST_PAIR,&p->z,t);
+ BSET(regused,t3);
+ BSET(regused,t4);
+ sety(f,l-1);
+ emit(f,"%s%d:\n",labprefix,++label);
+ emit(f,"\tlda\t%s,y\n",mregnames[qr]);
+ if(ind)
+ emit(f,"\tsta\t(%s),y\n",mregnames[LAST_PAIR]);
+ else{
+ emit(f,"\tsta\t");
+ emit_obj(f,&p->z,t);
+ emit(f,",y\n");
+ }
+ emit(f,"\tdey\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,label);
+ yval=255;
+ }else{
+ if((p->z.reg&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ if(p->z.reg==qr) ierror(0);
+ }
+ emit(f,"\tlda\t%s\n",mregnames[qr]);
+ store_lobyte(f,&p->z,t);
+ emit(f,"\tlda\t%s+1\n",mregnames[qr]);
+ store_hibyte(f,&p->z,t);
+ emit(f,"\tlda\t%s+2\n",mregnames[qr]);
+ do_byte3(f,"sta",&p->z,t);
+ if(!ISFPOINTER(t)){
+ emit(f,"\tlda\t%s+3\n",mregnames[qr]);
+ do_byte4(f,"sta",&p->z,t);
+ }
+ }
+ continue;
+ }
+ if(p->q1.reg)
+ store_acc(f,&p->z,t);
+ continue;
+ }
+ if(c==CALL){
+ int reg;
+
+ if(argsize<zm2l(p->q2.val.vmax)) argsize=zm2l(p->q2.val.vmax);
+
+ /*FIXME*/
+#if 0
+ if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+ if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+ stack=framesize+zum2ul(p->q1.v->fi->stack1);
+ }else
+ stack_valid=0;
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+ long of=va_offset(v)+localsize+rsavesize+argsize;
+ emit(f,"\tlda\t%s\n",mregnames[fp]);
+ if(of){
+ emit(f,"\tclc\n");
+ if(of&255)
+ emit(f,"\tadc\t#%d\n",(of&255));
+ }
+ emit(f,"\tldx\t%s+1\n",mregnames[fp]);
+ if(of&0xff00){
+ emit(f,"\tpha\n");
+ emit(f,"\ttxa\n");
+ emit(f,"\tadc\t#%d\n",(of>>8)&255);
+ emit(f,"\ttax\n");
+ emit(f,"\tpla\n");
+ }else if(of){
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ emit(f,"\tinx\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ continue;
+ }
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit(f,";startinline\n");
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ emit(f,";endinline\n");
+ }else if(p->q1.flags&DREFOBJ){
+ if(ISFPOINTER(p->q1.dtyp)){
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,LAST_PAIR,&p->q1,POINTER);
+ if(indirect(&p->q1)){
+ do_byte3(f,"lda",&p->q1,FPOINTER);
+ emit(f,"\ttay\n");
+ }else
+ do_byte3(f,"ldy",&p->q1,FPOINTER);
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ emit(f,"\tjsr\t%s__bankjsr\n",idprefix);
+ yval=NOVAL;
+ }else{
+ if(!(p->q1.flags®)) ierror(0);
+ emit(f,"\tjsr\t%s%d\n",labprefix,++label);
+ yval=NOVAL;
+ add_cmplist(label,p->q1.reg,JMPIND);
+ }
+ }else{
+ int tbank=-1;
+ if(p->q1.flags&VAR) tbank=bank(p->q1.v);
+ if(tbank!=cbank&&tbank>=0){
+ if(cbank>=0){
+ load_address(f,LAST_PAIR,&p->q1,t);
+ sety(f,tbank);
+ emit(f,"\tlda\t#%d\n",cbank);
+ emit(f,"\tjsr\t%s__bankjsr\n",idprefix);
+ yval=NOVAL;
+ continue;
+ }
+ sety(f,tbank);
+ emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+ yval=NOVAL;
+ }
+ if((p->q1.flags&VAR)&&!strcmp(p->q1.v->identifier,"_fmemcpy"))
+ emit(f,"\tlda\t#%d\n",cbank>=0?cbank:bankcnum);
+ emit(f,"\tjsr\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ pushed-=zm2l(p->q2.val.vmax);
+ if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS;
+ yval=NOVAL;
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(t==0) ierror(0);
+ if((p->q1.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)==LLONG){
+ int i;
+ eval_const(&p->q1.val,t);
+ for(i=0;i<8;i++){
+ emit(f,"\tlda\t#%d\n",zm2l(vmax)&255);
+ vmax=zmrshift(vmax,l2zm(8L));
+ if(c==PUSH||(p->z.flags&DREFOBJ)){
+ sety(f,i+((c==PUSH)?pushed:0));
+ emit(f,"\tsta\t(%s),y\n",(c==PUSH)?mregnames[sp]:mregnames[p->z.reg]);
+ }else{
+ p->z.val.vmax=zmadd(p->z.val.vmax,l2zm((long)i));
+ emit(f,"\tsta\t");
+ emit_lobyte(f,&p->z,t);
+ emit(f,"\n");
+ p->z.val.vmax=zmsub(p->z.val.vmax,l2zm((long)i));
+ }
+ }
+ if(c==PUSH) pushed+=8;
+ continue;
+ }
+
+ if(!zmleq(p->q2.val.vmax,l2zm(4L))){
+ long len=zm2l(p->q2.val.vmax);
+ int r1,r2,loops,looplab;
+ if(len>32767) ierror(0);
+ if(!NOBANKVARS){
+ int bq=-1,bz=-1,s=-1;
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR) bq=bank(p->q1.v);
+ if((p->z.flags&(VAR|DREFOBJ))==VAR) bz=bank(p->z.v);
+ if(((p->q1.flags&DREFOBJ)&&ISFPOINTER(p->q1.dtyp))||
+ ((p->z.flags&DREFOBJ)&&ISFPOINTER(p->z.dtyp))){
+ far_copy(f,p);
+ continue;
+ }
+ if(cbank<0){
+ if(bq>=0&&bz>=0){
+ if(bq!=bz){
+ far_copy(f,p);
+ continue;
+ }
+ s=bq;
+ }else{
+ if(bq>=0) s=bq;
+ if(bz>=0) s=bz;
+ }
+ if(s>=0){
+ sety(f,s);
+ emit(f,"\tjsr\t%s__bankswitch\n",idprefix);
+ yval=NOVAL;
+ }
+ }else{
+ if((bq>=0&&bq!=cbank)||(bz>=0&&bz!=cbank)){
+ far_copy(f,p);
+ continue;
+ }
+ }
+ }
+ get_acc(f,p,CHAR);
+ if((p->q1.flags&(DREFOBJ|KONST))==DREFOBJ){
+ if(p->q1.flags®){
+ r1=p->q1.reg;
+ if(!reg_pair(r1,&rp)) ierror(0);
+ if(len>128){
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tclc\n");
+ if(len&128)
+ emit(f,"\tadc\t#128\n");
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ if(len>255){
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tadc\t#%ld\n",(len>>8)&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ }else{
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ emit(f,"\tinc\t%s\n",mregnames[rp.r2]);
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }
+ }else
+ ierror(0);
+ }else if(!indirect(&p->q1)&&len<=128&&(p->q1.flags&(DREFOBJ|KONST))!=KONST){
+ r1=0;
+ }else{
+ Var *v=p->q1.v;
+ /*if((p->q1.flags&(VARADR|VAR))!=VAR) ierror(0);*/
+ r1=get_reg(f,p,POINTER);
+ if(len>128) p->q1.val.vmax=zmadd(p->q1.val.vmax,l2zm(len&0xff80));
+ load_address(f,r1,&p->q1,t);
+ if(len>128) p->q1.val.vmax=zmsub(p->q1.val.vmax,l2zm(len&0xff80));
+ }
+ if((p->z.flags&(DREFOBJ|KONST))==DREFOBJ){
+ if(p->z.flags®){
+ r2=p->z.reg;
+ if(!reg_pair(r2,&rp)) ierror(0);
+ if(len>128){
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tclc\n");
+ if(len&128)
+ emit(f,"\tadc\t#128\n");
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ if(len>255){
+ emit(f,"\tlda\t%s\n",mregnames[rp.r2]);
+ emit(f,"\tadc\t#%ld\n",(len>>8)&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ }else{
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ emit(f,"\tinc\t%s\n",mregnames[rp.r2]);
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }
+ }else
+ ierror(0);
+ }else if(c==PUSH){
+ if(len<=128&&pushed==0){
+ r2=sp;
+ }else{
+ r2=get_reg(f,p,POINTER);
+ if(!reg_pair(r2,&rp)) ierror(0);
+ emit(f,"\tlda\t%s\n",mregnames[sp]);
+ emit(f,"\tclc\n");
+ if(((pushed+(len&128))&255)!=0)
+ emit(f,"\tadc\t#%ld\n",(pushed+(len&128))&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tlda\t%s\n",mregnames[sp2]);
+ emit(f,"\tadc\t#%ld\n",((pushed+len)>>8)&255);
+ emit(f,"\tsta\t%s\n",mregnames[rp.r2]);
+ }
+ }else if(!indirect(&p->z)&&len<=128){
+ r2=0;
+ }else{
+ Var *v=p->z.v;
+ r2=get_reg(f,p,POINTER);
+ if(len>128) p->z.val.vmax=zmadd(p->z.val.vmax,l2zm(len&0xff80));
+ load_address(f,r2,&p->z,t);
+ if(len>128) p->z.val.vmax=zmsub(p->z.val.vmax,l2zm(len&0xff80));
+ }
+ if(len>128){
+ get_acc(f,p,POINTER); /* get x */
+ emit(f,"\tldx\t#%ld\n",((len>>7)+1)&255);
+ }
+ sety(f,(len-1)&127);
+ if((optsize&&len>4)||len>8){
+ emit(f,"%s%d:\n",labprefix,looplab=++label);
+ if(optsize)
+ loops=1;
+ else{
+ if((len&3)==0)
+ loops=4;
+ else if((len&1)==0)
+ loops=2;
+ else
+ loops=1;
+ }
+ }else
+ loops=len;
+ if(r1&&!reg_pair(r1,&rp)) ierror(0);
+ if(r2&&!reg_pair(r2,&rp2)) ierror(0);
+ for(i=0;i<loops;i++){
+ if(r1)
+ emit(f,"\tlda\t(%s),y\n",mregnames[rp.r1]);
+ else{
+ emit(f,"\tlda\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,",y\n");
+ }
+ if(r2)
+ emit(f,"\tsta\t(%s),y\n",mregnames[rp2.r1]);
+ else{
+ emit(f,"\tsta\t");
+ emit_obj(f,&p->z,t);
+ emit(f,",y\n");
+ }
+ emit(f,"\tdey\n");
+ }
+ if(loops!=len){
+ emit(f,"\tbpl\t%s%d\n",labprefix,label);
+ }
+ if(len>128){
+ emit(f,"\tlda\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tsec\n");
+ emit(f,"\tsbc\t#128\n");
+ emit(f,"\tsta\t%s\n",mregnames[rp.r1]);
+ emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+ emit(f,"\tdec\t%s\n",mregnames[rp.r2]);
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tlda\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tsec\n");
+ emit(f,"\tsbc\t#128\n");
+ emit(f,"\tsta\t%s\n",mregnames[rp2.r1]);
+ emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+ emit(f,"\tdec\t%s\n",mregnames[rp2.r2]);
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tldy\t#127\n");
+ emit(f,"\tdex\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,looplab);
+ }
+ yval=NOVAL;
+ if(c==PUSH)
+ pushed+=zm2l(p->q2.val.vmax);
+ continue;
+ }
+ if(c==PUSH){
+ get_acc(f,p,CHAR);
+ load_lobyte(f,&p->q1,t);
+ sety(f,pushed);
+ emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+ if(!zmleq(p->q2.val.vmax,Z1)){
+ load_hibyte(f,&p->q1,t);
+ sety(f,pushed+1);
+ emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+ }
+ if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+ do_byte3(f,"lda",&p->q1,t);
+ sety(f,pushed+2);
+ emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+ }
+ if(!zmleq(p->q2.val.vmax,l2zm(3L))){
+ do_byte4(f,"lda",&p->q1,t);
+ sety(f,pushed+3);
+ emit(f,"\tsta\t(%s),y\n",mregnames[sp]);
+ }
+
+ pushed+=zm2l(p->q2.val.vmax);
+ continue;
+ }
+ if(c==ASSIGN){
+ if(isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg) continue;
+ if(isacc(q1)){
+ if(p->q1.reg==rax) get_acc(f,p,CHAR);
+ store_acc(f,&p->z,t);
+ continue;
+ }
+ get_acc(f,p,CHAR);
+ if(0/*ISCHAR(t)*/){
+ load_acc(f,&p->q1,t);
+ store_acc(f,&p->z,t);
+ }else{
+ // TODO: PGS: Use AXYZ for 32-bit copy if appropriate
+ // TOGO: PGS: Consider using AXYZ for load, even for 16 or 24-bit values
+ if(!zmleq(p->q2.val.vmax,l2zm(3L))){
+ do_byte4(f,"lda",&p->q1,t);
+ do_byte4(f,"sta",&p->z,t);
+ }
+ if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+ do_byte3(f,"lda",&p->q1,t);
+ do_byte3(f,"sta",&p->z,t);
+ }
+ if(!zmleq(p->q2.val.vmax,l2zm(1L))){
+ load_hibyte(f,&p->q1,t);
+ store_hibyte(f,&p->z,t);
+ }
+ load_lobyte(f,&p->q1,t);
+ store_lobyte(f,&p->z,t);
+ }
+ }
+ continue;
+ }
+ if(c==ADDRESS){
+ long o=real_offset(&p->q1);
+ get_acc(f,p,CHAR);
+ emit(f,"\tlda\t%s\n",mregnames[fp1]);
+ if(o){
+ emit(f,"\tclc\n");
+ if((o&255)!=0)
+ emit(f,"\tadc\t#%ld\n",real_offset(&p->q1)&255);
+ }
+ store_lobyte(f,&p->z,t);
+ if(isacc(z)) emit(f,"\tpha\n");
+ emit(f,"\tlda\t%s\n",mregnames[fp2]);
+ if(o!=0)
+ emit(f,"\tadc\t#%ld\n",real_offset(&p->q1)>>8&255);
+ store_hibyte(f,&p->z,t);
+ if(isacc(z)) emit(f,"\tpla\n");
+ continue;
+ }
+
+ if(c==COMPARE||c==TEST){
+ IC *branch=p->next;
+ int pacc=0,bc,bout;
+ while(branch){
+ if(branch->code>=BEQ&&branch->code<BRA)
+ break;
+ if(branch->code!=FREEREG&&branch->code!=ALLOCREG&&branch->code!=NOP)
+ ierror(0);
+ branch=branch->next;
+ }
+ bc=branch->code;
+ bout=branch->typf;
+ if(c==TEST){
+ p->q2.flags=KONST;
+ gval.vmax=Z0;
+ eval_const(&gval,MAXINT);
+ insert_const(&p->q2.val,t);
+ }
+ if(ieee&&ISFLOAT(t)){
+ if(!ieee) ierror(0);
+ t&=NQ;
+ if(regs[LAST_PAIR]) ierror(0);
+ regs[LAST_PAIR]=1;
+ if(regs[ra]||regs[rax])
+ ierror(0);
+ load_address(f,LAST_PAIR,&p->q2,t);
+ BSET(regused,t3);
+ BSET(regused,t4);
+ emit(f,"\tjsr\t%s__fload%c\n",idprefix,(t==FLOAT?'s':'d'));
+ yval=NOVAL;
+ load_address(f,LAST_PAIR,&p->q1,t);
+ emit(f,"\tjsr\t%s__fcmp%c\n",idprefix,(t==FLOAT?'s':'d'));
+ yval=NOVAL;
+ regs[LAST_PAIR]=0;
+ if(bc==BLT||bc==BLE)
+ emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+ else if(bc==BGT|bc==BGE)
+ emit(f,"\tbvs\t%s%d\n",labprefix,bout);
+ if(bc==BEQ||bc==BLE||bc==BGE)
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ continue;
+ }
+ if(ISCHAR(t)){
+ char *s;
+ if(pacc=cmp_get_acc(f,p,branch))
+ bout=++label;
+ load_acc(f,&p->q1,t);
+ if(bc==BEQ||bc==BNE||(t&UNSIGNED)){
+ s="cmp";
+ }else{
+ if(bc==BLT||bc==BGE)
+ emit(f,"\tsec\n");
+ else
+ emit(f,"\tclc\n");
+ s="sbc";
+ }
+ if(c==TEST)
+ emit(f,"\t%s\t#0\n",s);
+ else
+ do_lobyte(f,s,&p->q2,t);
+ if(bc==BEQ)
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ else if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ else if(t&UNSIGNED){
+ if(bc==BLT)
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ else if(bc==BGE)
+ emit(f,"\tbcs\t%s%d\n",labprefix,bout);
+ else if(bc==BLE){
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ }else if(bc==BGT){
+ emit(f,";\n\tbeq\t%s%d\n",labprefix,++label);
+ emit(f,"\tbcs\t%s%d\n",labprefix,bout);
+ emit(f,"%s%d:\n",labprefix,label);
+ }else
+ ierror(0);
+ }else{
+ emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+ emit(f,"\teor\t#128\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(bc==BLT||bc==BLE)
+ emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+ else
+ emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+ }
+ if(pacc){
+ reload_acc(f);
+ add_cmplist(bout,branch->typf,pacc);
+ }
+ continue;
+ }else if(bc==BEQ||bc==BNE||(t&UNSIGNED)||ISFPOINTER(t)){
+ int in=0;
+ if(pacc=cmp_get_acc(f,p,branch))
+ bout=++label;
+
+ // PGS Check for special cases of comparing to constants
+ if(!(ISLONG(t)||ISFPOINTER(t)||isacc(q1))) {
+ // Is a 16-bit value
+ if (p->q2.flags&KONST) {
+ if (!(p->q2.flags&DREFOBJ)) {
+ eval_const(&p->q2.val,t);
+ if(ISFLOAT(t)) cnv_fp();
+ if (zm2l(vmax)==0x100) {
+ if (bc==BGE) {
+ // >= $100 we can check by just reading the 2nd byte
+ // If non-zero, then we take the branch
+ do_hibyte(f,"lda",&p->q1,t);
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ continue;
+ } else if (bc==BLT) {
+ // <$100 we can check by just reading the 2nd byte
+ // And if zero, then we take the branch
+ do_hibyte(f,"lda",&p->q1,t);
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ continue;
+ }
+ } else if (zm2l(vmax)<0x100) {
+ // Values <$100 we can do almost as simply, but we have to
+ // also check the low byte for exceptions.
+ // XXX PGS TODO
+
+ }
+ }
+ }
+ }
+
+ // Far-Pointers are 32-bit on M65
+ if(ISLONG(t)||ISFPOINTER(t)){
+ do_byte4(f,"lda",&p->q1,t);
+ if(c==TEST)
+ emit(f,"\tcmp\t#0\n");
+ else
+ do_byte4(f,"cmp",&p->q2,t);
+ if(bc==BEQ)
+ emit(f,"\tbne\t%s%d\n",labprefix,in=++label);
+ else if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ else if(bc==BLT||bc==BLE){
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ emit(f,"\tbne\t%s%d\n",labprefix,in=++label);
+ }else if(bc==BGE||bc==BGT){
+ emit(f,"\tbcc\t%s%d\n",labprefix,in=++label);
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ }else
+ ierror(0);
+ }
+ if(ISLONG(t)||ISFPOINTER(t)){
+ do_byte3(f,"lda",&p->q1,t);
+ if(c==TEST)
+ emit(f,"\tcmp\t#0\n");
+ else
+ do_byte3(f,"cmp",&p->q2,t);
+ if(bc==BEQ)
+ emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+ else if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ else if(bc==BLT||bc==BLE){
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+ }else if(bc==BGE||bc==BGT){
+ emit(f,"\tbcc\t%s%d\n",labprefix,in?in:(in=++label));
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ }else
+ ierror(0);
+ }
+ if(isacc(q1)){
+ if(!indirect(&p->q2)){
+ do_hibyte(f,"cpx",&p->q2,t);
+ }else{
+ int r=get_reg(f,p,CHAR);
+ emit(f,"\tpha\n");
+ load_hibyte(f,&p->q2,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ emit(f,"\tpla\n");
+ emit(f,"\tcpx\t%s\n",mregnames[r]);
+ }
+ }else{
+ load_hibyte(f,&p->q1,t);
+ if(c==TEST)
+ emit(f,"\tcmp\t#0\n");
+ else
+ do_hibyte(f,"cmp",&p->q2,t);
+ }
+ if(bc==BEQ)
+ emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+ else if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ else if(bc==BLT||bc==BLE){
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ emit(f,"\tbne\t%s%d\n",labprefix,in?in:(in=++label));
+ }else if(bc==BGE||bc==BGT){
+ emit(f,"\tbcc\t%s%d\n",labprefix,in?in:(in=++label));
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ }else
+ ierror(0);
+ load_lobyte(f,&p->q1,t);
+ if(c==TEST)
+ emit(f,"\tcmp\t#0\n");
+ else
+ do_lobyte(f,"cmp",&p->q2,t);
+ if(bc==BEQ)
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ else if(bc==BNE)
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ else if(bc==BLT)
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ else if(bc==BGE)
+ emit(f,"\tbcs\t%s%d\n",labprefix,bout);
+ else if(bc==BLE){
+ emit(f,"\tbcc\t%s%d\n",labprefix,bout);
+ emit(f,"\tbeq\t%s%d\n",labprefix,bout);
+ }else if(bc==BGT){
+ emit(f,"\tbcc\t%s%d\n",labprefix,in);
+ emit(f,"\tbne\t%s%d\n",labprefix,bout);
+ }else
+ ierror(0);
+ if(in)
+ emit(f,"%s%d:\n",labprefix,in);
+ if(pacc){
+ reload_acc(f);
+ add_cmplist(bout,branch->typf,pacc);
+ }
+ continue;
+ }else{
+ if(bc==BGT||bc==BLE){
+ obj o;
+ if(isacc(q1)){
+ int r;
+ if(pacc=cmp_get_acc(f,p,branch))
+ bout=++label;
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ load_lobyte(f,&p->q2,t);
+ emit(f,"\tcmp\t%s\n",mregnames[r]);
+ emit(f,"\tstx\t%s\n",mregnames[r]);
+ load_hibyte(f,&p->q2,t);
+ emit(f,"\tsbc\t%s\n",mregnames[r]);
+ emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+ emit(f,"\teor\t#128\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(bc==BGT)
+ emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+ else
+ emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+ if(pacc){
+ reload_acc(f);
+ add_cmplist(bout,branch->typf,pacc);
+ }
+ continue;
+ }else{
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ if(bc==BGT) bc=BLT; else bc=BGE;
+ }
+ }
+ if(pacc=cmp_get_acc(f,p,branch))
+ bout=++label;
+ if(ISLONG(t)){
+ load_lobyte(f,&p->q1,t);
+ do_lobyte(f,"cmp",&p->q2,t);
+ load_hibyte(f,&p->q1,t);
+ do_hibyte(f,"sbc",&p->q2,t);
+ do_byte3(f,"lda",&p->q1,t);
+ do_byte3(f,"sbc",&p->q2,t);
+ do_byte4(f,"lda",&p->q1,t);
+ do_byte4(f,"sbc",&p->q2,t);
+ }else{
+ load_lobyte(f,&p->q1,t);
+ do_lobyte(f,"cmp",&p->q2,t);
+ load_hibyte(f,&p->q1,t);
+ do_hibyte(f,"sbc",&p->q2,t);
+ }
+ emit(f,"\tbvc\t%s%d\n",labprefix,++label);
+ emit(f,"\teor\t#128\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(bc==BLT)
+ emit(f,"\tbmi\t%s%d\n",labprefix,bout);
+ else if(bc==BGE)
+ emit(f,"\tbpl\t%s%d\n",labprefix,bout);
+ else
+ ierror(0);
+ if(pacc){
+ reload_acc(f);
+ add_cmplist(bout,branch->typf,pacc);
+ }
+ continue;
+ }
+ ierror(0);
+ }
+ if((c==ADD||c==SUB||c==ADDI2P||c==SUBIFP)&&compare_objects(&p->q1,&p->z)&&!indirect(&p->q1)&&isconst(q2)&&!isacc(z)){
+ long l;
+ eval_const(&p->q2.val,q2typ(p));
+ l=zm2l(vmax);
+ if(c==ADDI2P/*&&(t2&NQ)==POINTER*/) {c=ADD;t=UNSIGNED|INT;}
+ if(c==SUBIFP/*&&(t2&NQ)==POINTER*/) {c=SUB;t=UNSIGNED|INT;}
+ if(c==SUB||c==SUBIFP) l=-l;
+ /*TODO: allow larger types */
+ if(l<3&&l>-3&&(t&NQ)<=INT){
+ if(l<0){
+ get_acc(f,p,CHAR);
+ incmem(f,&p->z,t,SUB,-l);
+ }else
+ incmem(f,&p->z,t,ADD,l);
+ continue;
+ }
+ }
+
+ if((c==LSHIFT||c==RSHIFT)&&isreg(q1)&&isreg(z)&&isconst(q2)&&p->q1.reg==p->z.reg&&p->z.reg!=ra&&p->z.reg!=rax){
+ long l;
+ eval_const(&p->q2.val,q2typ(p));
+ l=zm2l(vmax);
+ /*TODO: allow larger types */
+ if(l<5&&(t&NQ)<=INT){
+ if(c==RSHIFT&&!(t&UNSIGNED))
+ get_acc(f,p,CHAR);
+ incmem(f,&p->z,t,c,l);
+ continue;
+ }
+ }
+
+ if(c==LSHIFT||c==RSHIFT){
+ long l=-1;int loop=0,r,r2,r3,outl=0;
+ if(isconst(q2)){
+ eval_const(&p->q2.val,q2typ(p));
+ l=zm2l(vmax);
+ loop=0;
+ }else
+ loop=1;
+ if(l>=0&&optsize){
+ if(c==LSHIFT&&(l&7)>6)
+ loop=1;
+ else if(c==RSHIFT&&(t&UNSIGNED)&&(l&7)>3)
+ loop=1;
+ else if(c==RSHIFT&&!(t&UNSIGNED)&&(l&7)>2)
+ loop=1;
+ }
+
+ if(!ISCHAR(t))
+ r=get_reg(f,p,CHAR);
+ if(ISLONG(t)){
+ r2=get_reg(f,p,CHAR);
+ r3=get_reg(f,p,CHAR);
+ }
+ if(ISLONG(t)){
+ get_acc(f,p,CHAR);
+ if(l>=24){
+ if(c==LSHIFT){
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ emit(f,"\tlda\t#0\n");
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ }else if(c==RSHIFT&&!(t&UNSIGNED)){
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ sety(f,0);
+ emit(f,"\tcmp\t#0\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdey\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tsty\t%s\n",mregnames[r]);
+ emit(f,"\tsty\t%s\n",mregnames[r2]);
+ emit(f,"\ttya\n");
+ yval=NOVAL;
+ }else{
+ emit(f,"\tlda\t#0\n");
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ do_byte4(f,"lda",&p->q1,t);
+
+ }
+ }else if(l>=16){
+ if(c==LSHIFT){
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ emit(f,"\tlda\t#0\n");
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ }else if(c==RSHIFT&&!(t&UNSIGNED)){
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ sety(f,0);
+ emit(f,"\tcmp\t#0\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdey\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\tsty\t%s\n",mregnames[r]);
+ emit(f,"\ttya\n");
+ yval=NOVAL;
+ }else{
+ emit(f,"\tlda\t#0\n");
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ do_byte3(f,"lda",&p->q1,t);
+
+ }
+ }else if(l>=8){
+ if(c==LSHIFT){
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ emit(f,"\tlda\t#0\n");
+ }else if(c==RSHIFT&&!(t&UNSIGNED)){
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ sety(f,0);
+ emit(f,"\tcmp\t#0\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdey\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ emit(f,"\ttya\n");
+ yval=NOVAL;
+ }else{
+ emit(f,"\tlda\t#0\n");
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ load_hibyte(f,&p->q1,t);
+
+ }
+ }else if(c==RSHIFT&&!(t&UNSIGNED)){
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ do_byte4(f,"lda",&p->q1,t);
+ }else{
+ do_byte4(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r3]);
+ do_byte3(f,"lda",&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r2]);
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tsta\t%s\n",mregnames[r]);
+ load_lobyte(f,&p->q1,t);
+ }
+ }else
+ get_acc(f,p,t);
+ if(!ISLONG(t)){
+ if(l>=8){
+ if(!ISSHORT(t)) ierror(0);
+ if(c==LSHIFT){
+ if(indirect(&p->q1)){
+ load_lobyte(f,&p->q1,t);
+ emit(f,"\ttax\n");
+ emit(f,"\tlda\t#0\n");
+ }else{
+ if(isacc(q1))
+ emit(f,"\ttax\n");
+ else
+ do_lobyte(f,"ldx",&p->q1,t);
+ emit(f,"\tlda\t#0\n");
+ }
+ }else{
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\tldx\t#0\n");
+ if(!(t&UNSIGNED)){
+ emit(f,"\tcmp\t#0\n");
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdex\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }
+ }else
+ load_acc(f,&p->q1,t);
+ }
+ if(ISSHORT(t))
+ emit(f,"\tstx\t%s\n",mregnames[r]);
+ if(l>=0) l&=7;
+ if(loop){
+ if(l>=0)
+ sety(f,l);
+ else{
+ if(indirect(&p->q2)){
+ emit(f,"\tpha\n");
+ load_lobyte(f,&p->q2,q2typ(p));
+ emit(f,"\ttay\n");
+ emit(f,"\tpla\n");
+ emit(f,"\tcpy\t#0\n");
+ }else{
+ emit(f,"\tldy\t");
+ emit_lobyte(f,&p->q2,q2typ(p));
+ emit(f,"\n");
+ }
+ outl=++label;
+ emit(f,"\tbeq\t%s%d\n",labprefix,outl);
+ }
+ emit(f,"%s%d:\n",labprefix,++label);
+ }else{
+ if(ISCHAR(t))
+ l&=7;
+ else if(ISSHORT(t))
+ l&=15;
+ else
+ l&=31;
+ }
+ while(l>0||loop){
+ if(c==LSHIFT){
+ emit(f,"\tasl\n");
+ if(!ISCHAR(t))
+ emit(f,"\trol\t%s\n",mregnames[r]);
+ if(ISLONG(t)){
+ emit(f,"\trol\t%s\n",mregnames[r2]);
+ emit(f,"\trol\t%s\n",mregnames[r3]);
+ }
+ }else if(t&UNSIGNED){
+ emit(f,"\tclc\n");
+ if(ISLONG(t)){
+ emit(f,"\tror\t%s\n",mregnames[r3]);
+ emit(f,"\tror\t%s\n",mregnames[r2]);
+ }
+ if(!ISCHAR(t))
+ emit(f,"\tror\t%s\n",mregnames[r]);
+ emit(f,"\tror\n");
+ }else{
+ if(ISLONG(t)){
+ emit(f,"\tcmp\t#128\n");
+ emit(f,"\tror\n");
+ emit(f,"\tror\t%s\n",mregnames[r]);
+ emit(f,"\tror\t%s\n",mregnames[r2]);
+ emit(f,"\tror\t%s\n",mregnames[r3]);
+ }else{
+ if(!ISCHAR(t)){
+ emit(f,"\tcpx\t#128\n");
+ emit(f,"\tror\t%s\n",mregnames[r]);
+ }else
+ emit(f,"\tcmp\t#128\n");
+ emit(f,"\tror\n");
+ }
+ }
+ if(loop){
+ emit(f,"\tdey\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,label);
+ if(outl) emit(f,"%s%d:\n",labprefix,outl);
+ yval=0;
+ break;
+ }
+ l--;
+ }
+ if(ISLONG(t)){
+ if(c==RSHIFT&&!(t&UNSIGNED)){
+ do_byte4(f,"sta",&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r]);
+ do_byte3(f,"sta",&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r2]);
+ store_hibyte(f,&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r3]);
+ store_lobyte(f,&p->z,t);
+ }else{
+ store_lobyte(f,&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r]);
+ store_hibyte(f,&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r2]);
+ do_byte3(f,"sta",&p->z,t);
+ emit(f,"\tlda\t%s\n",mregnames[r3]);
+ do_byte4(f,"sta",&p->z,t);
+ }
+ }else{
+ if(!ISCHAR(t))
+ emit(f,"\tldx\t%s\n",mregnames[r]);
+ if(ISCHAR(t)||indirect(&p->z))
+ store_acc(f,&p->z,t);
+ else{
+ store_lobyte(f,&p->z,t);
+ if(!isreg(z)||p->z.reg!=rax){
+ emit(f,"\tstx\t");
+ emit_hibyte(f,&p->z,t);
+ emit(f,"\n");
+ }
+ }
+ }
+ continue;
+ }
+
+ if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)||c==ADDI2P||c==SUBIFP){
+ char *s;int t2=t,pt=p->typf2;
+ if(!isacc(z))
+ get_acc(f,p,CHAR);
+ if(c==ADDI2P||c==SUBIFP){
+ if(c==ADDI2P) c=ADD; else c=SUB;
+ t=UNSIGNED|INT;
+ if((pt&NQ)==POINTER&&(p->q1.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q1.val,POINTER);
+ insert_const(&p->q1.val,UNSIGNED|INT);
+ }
+ }
+ if(c>=OR&&c<=AND)
+ s=logicals[c-OR];
+ else
+ s=arithmetics[c-LSHIFT];
+
+ if(ISFLOAT(t)){
+ if(!ieee) ierror(0);
+ t&=NQ;
+ if(regs[LAST_PAIR]) ierror(0);
+ get_acc(f,p,INT);
+ regs[LAST_PAIR]=1;
+ load_address(f,LAST_PAIR,&p->q1,t);
+ BSET(regused,t3);
+ BSET(regused,t4);
+ emit(f,"\tjsr\t%s__fload%c\n",idprefix,(t==FLOAT?'s':'d'));
+ yval=NOVAL;
+ load_address(f,LAST_PAIR,&p->q2,t);
+ emit(f,"\tjsr\t%s__f%s%c\n",idprefix,ename[c],(t==FLOAT?'s':'d'));
+ yval=NOVAL;
+ load_address(f,LAST_PAIR,&p->z,t);
+ emit(f,"\tjsr\t%s__fstore%c\n",idprefix,(t==FLOAT?'s':'d'));
+ yval=NOVAL;
+ regs[LAST_PAIR]=0;
+ continue;
+ }else if(ISLONG(t)){
+ if(c==ADD) emit(f,"\tclc\n");
+ if(c==SUB) emit(f,"\tsec\n");
+ load_lobyte(f,&p->q1,t);
+ do_lobyte(f,s,&p->q2,t);
+ store_lobyte(f,&p->z,t);
+ load_hibyte(f,&p->q1,t);
+ do_hibyte(f,s,&p->q2,t);
+ store_hibyte(f,&p->z,t);
+ do_byte3(f,"lda",&p->q1,t);
+ do_byte3(f,s,&p->q2,t);
+ do_byte3(f,"sta",&p->z,t);
+ do_byte4(f,"lda",&p->q1,t);
+ do_byte4(f,s,&p->q2,t);
+ do_byte4(f,"sta",&p->z,t);
+ continue;
+ }else if(ISCHAR(t)){
+ load_acc(f,&p->q1,t);
+ if(c==ADD) emit(f,"\tclc\n");
+ if(c==SUB) emit(f,"\tsec\n");
+ do_lobyte(f,s,&p->q2,t);
+ store_acc(f,&p->z,t);
+ }else if(c==ADD||c==SUB){
+ int a,r;long l=1;
+ if(isconst(q2)){
+ eval_const(&p->q2.val,t2);
+ l=zm2l(vmax);
+ l&=0xff00;
+ }
+ if(isreg(z)&&p->z.reg==rax) a=1; else a=0;
+ if((t2&NU)==CHAR&&(p->q2.flags&(KONST|DREFOBJ))!=KONST){
+ emit(f,"\tldx\t#0\n");
+ }
+ if((t2&NU)==CHAR&&(p->q2.flags&(KONST|DREFOBJ))!=KONST){
+ load_lobyte(f,&p->q2,t);
+ emit(f,"\tbpl\t%s%d\n",labprefix,++label);
+ emit(f,"\tdex\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ if(c==ADD){
+ if(c==ADD) emit(f,"\tclc\n"); else emit(f,"\tsec\n");
+ do_lobyte(f,s,&p->q1,t);
+ if(isacc(z))
+ emit(f,"\tpha\n");
+ else
+ store_lobyte(f,&p->z,t);
+ emit(f,"\ttxa\n");
+ do_hibyte(f,s,&p->q1,t);
+ store_hibyte(f,&p->z,t);
+ if(ISFPOINTER(pt)&&!compare_objects(&p->q1,&p->z)){
+ do_byte3(f,"lda",&p->q1,pt);
+ do_byte3(f,"sta",&p->z,pt);
+ }
+ if(isacc(z))
+ emit(f,"\tpla\n");
+ continue;
+ }
+ r=get_reg(f,p,CHAR);
+ emit(f,"\tstx\t%s\n",mregnames[r]);
+ }
+ load_lobyte(f,&p->q1,t);
+ if(c==ADD) emit(f,"\tclc\n"); else emit(f,"\tsec\n");
+ do_lobyte(f,s,&p->q2,t2);
+ store_lobyte(f,&p->z,t);
+ if(l==0&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg){
+ if(c==ADD){
+ emit(f,"\tbcc\t%s%d\n",labprefix,++label);
+ if(a)
+ emit(f,"\tinx\n");
+ else{
+ /*if(!reg_pair(p->z.reg,&rp)) ierror(0);*/
+ emit(f,"\tinc\t%s+1\n",mregnames[p->z.reg]);
+ }
+ }else{
+ emit(f,"\tbcs\t%s%d\n",labprefix,++label);
+ if(a)
+ emit(f,"\tdex\n");
+ else{
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ emit(f,"\tdec\t%s\n",mregnames[rp.r2]);
+ }
+ }
+ emit(f,"%s%d:\n",labprefix,label);
+ }else{
+ if(a==1) emit(f,"\tpha\n");
+ if((t2&NQ)==CHAR){
+ if(t2&UNSIGNED){
+ load_hibyte(f,&p->q1,t);
+ emit(f,"\t%s\t#0\n",s);
+ }else{
+ load_hibyte(f,&p->q1,t);
+ if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,t2);
+ if(zmleq(Z0,vmax))
+ emit(f,"\t%s\t#0\n",s);
+ else
+ emit(f,"\t%s\t#255\n",s);
+ }else{
+ emit(f,"\t%s\t%s\n",s,mregnames[r]);
+ }
+ }
+ }else{
+ load_hibyte(f,&p->q1,t);
+ do_hibyte(f,s,&p->q2,t2);
+ }
+ store_hibyte(f,&p->z,t);
+ if(a==1) emit(f,"\tpla\n");
+ if(ISFPOINTER(pt)&&p->code!=SUBPFP){
+ if(!compare_objects(&p->q1,&p->z)){
+ do_byte3(f,"lda",&p->q1,FPOINTER);
+ do_byte3(f,"sta",&p->z,FPOINTER);
+ }
+ }
+ }
+ }else{
+ if(isacc(q1))
+ emit(f,"\tpha\n");
+ load_hibyte(f,&p->q1,t);
+ do_hibyte(f,s,&p->q2,t);
+ store_hibyte(f,&p->z,t);
+ if(isacc(q1))
+ emit(f,"\tpla\n");
+ load_lobyte(f,&p->q1,t);
+ do_lobyte(f,s,&p->q2,t);
+ store_lobyte(f,&p->z,t);
+ }
+ continue;
+ }
+ pric2(stdout,p);
+ ierror(0);
+ }
+
+ function_bottom(f,v,localsize);
+
+ for(c=1;c<=MAXR;c++){
+ if(regsa[c]||regused[c]){
+ BSET(regs_modified,c);
+ }
+ }
+
+ if(stack_valid){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=stack;
+ }
+ }
+
+ free_IC(mi);
+
+ emit(f,"; stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int code,int typ)
+{
+ if(code==COMPARE/*||code==MULT*/||code==ADD||code==SUB||code==AND||code==OR||code==XOR||code==LSHIFT||code==RSHIFT/*||code==MINUS*/||code==KOMPLEMENT)
+ return 1;
+
+ return 0;
+}
+
+static int fattr(type *p,char *s)
+{
+ if(p->attr&&strstr(p->attr,s))
+ return 1;
+ if(p->next)
+ return fattr(p->next,s);
+ else
+ return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+ int f;
+
+ if(vararg)
+ return 0;
+ f=t->flags&NQ;
+ if(OLDFP&&ISFLOAT(f)) return 0;
+ if(d&&fattr(d,"__stackparms__"))
+ return 0;
+ if(d&&fattr(d,"__cc65__")){
+ m->regs++;
+ printf("arg=%d cnt=%d\n",m->regs,d->exact->count);
+ if(m->regs==d->exact->count-1){
+ if(ISCHAR(t->flags))
+ return ra;
+ if(ISSHORT(t->flags))
+ return rax;
+ }
+ return 0;
+ }
+ if(ISCHAR(f)){
+ if(!t->exact){
+ if(m->regs>=GPR_ARGS-1)
+ return 0;
+ f=FIRST_GPR+m->regs;
+ m->regs+=2;
+ return f;
+ }else{
+ if(m->regs>=GPR_ARGS)
+ return 0;
+ else
+ return FIRST_GPR+m->regs++;
+ }
+ }
+ if(ISSHORT(f)||f==POINTER){
+ if(m->regs>=GPR_ARGS-1)
+ return 0;
+ else{
+ if(m->regs&1) m->regs+=1;
+ m->regs+=2;
+ return FIRST_PAIR+m->regs/2-1;
+ }
+ }
+ if(f==FPOINTER||f==LONG||f==FLOAT||(!ieee&&(f==DOUBLE||f==LDOUBLE))){
+ if(m->bregs>=4)
+ return 0;
+ else
+ return FIRST_BIG+m->bregs++;
+ }
+ if(f==LLONG||(ieee&&(f==DOUBLE||f==LDOUBLE))){
+ if(m->bregs>=3)
+ return 0;
+ else{
+ if(m->bregs&1) m->bregs++;
+ m->bregs+=2;
+ return FIRST_BIGP+m->bregs/2-1;
+ }
+ }
+ return 0;
+}
+
+int handle_pragma(const char *s)
+{
+ static char sec[SECLEN];
+ int i;
+ if(sscanf(s,"section %127s",sec)==1){
+ if(!strcmp(sec,"default"))
+ use_sec=0;
+ else
+ use_sec=sec;
+ return 1;
+ }
+ if(sscanf(s,"bank %d",&i)==1){
+ use_bank=i;
+ return 1;
+ }
+}
+void cleanup_cg(FILE *f)
+{
+ int i;
+ struct fpconstlist *p=firstfpc;
+
+ if(f&&p){
+ emit(f,rodataname);emit(f,"\n");
+ section=RODATA;
+ }
+ while(p=firstfpc){
+ emit(f,"%s%d:\n\tword\t",labprefix,p->label);
+ if(ieee)
+ emit_ieee(f,&p->val,p->t);
+ else{
+ int words=zm2l(sizetab[p->t&NQ])/2;
+ eval_const(&p->val,p->t);
+ if(ISFLOAT(p->t)) cnv_fp();
+ for(i=0;i<words;i++){
+ emit(f,"%ld",zm2l(vmax)&0xffff);
+ if(i<words-1){emit(f,",");vmax=zmrshift(vmax,l2zm(16L));}
+ }
+ emit(f,"\n");
+ /*emit(f,"%ld,%ld\n",zm2l(vmax)&0xffff,zm2l(zmrshift(vmax,l2zm(16L)))&0xffff);*/
+ }
+ firstfpc=p->next;
+ free(p);
+ }
+
+ emit(f,"\tzpage\t%s\n",mregnames[sp]);
+ for(i=FIRST_GPR;i<=LAST_GPR;i++)
+ emit(f,"\tzpage\t%s\n",mregnames[i]);
+ for(i=FIRST_BIG;i<=LAST_BIG;i++)
+ emit(f,"\tzpage\t%s\n",mregnames[i]);
+
+}
+void cleanup_db(FILE *f)
+{
+ if(f) section=-1;
+}
+
+static char *zops[]={
+ "adc","and","asl","bit","eor","lda","ora",
+ "tax","txa","tay","tya","sbc"};
+
+static int setszflag(char *op)
+{
+ int i;
+ for(i=0;i<sizeof(zops)/sizeof(zops[0]);i++)
+ if(!strcmp(op,zops[i]))
+ return 1;
+ return 0;
+}
+
+
+enum peepf { NEEDSAME = 1, REMOVE1ST = 2};
+struct peeps {char *s1,*s2,*r;enum peepf flags;};
+
+
+
+int emit_peephole(void)
+{
+ int entries,i,j;
+ char *asmline[EMIT_BUF_DEPTH];
+ char buf1[1024],buf2[1024];
+ char op1[8],op2[8];
+ static char ca[1024],cx[1024],cy[1024],cz[1024];
+ static int rm,disabled;
+
+ fprintf(stderr,"Called emit_peephole()\n");
+
+ static struct peeps elim[]={
+ "lda","sta",0,NEEDSAME,
+ "ldx","stx",0,NEEDSAME,
+ "sta","sta",0,NEEDSAME,
+ "stx","stx",0,NEEDSAME,
+ "sta","lda",0,NEEDSAME,
+ "stx","ldx",0,NEEDSAME,
+ "txa","tax",0,0,
+ "tax","txa",0,0,
+ "lda","lda",0,REMOVE1ST,
+ "ldx","ldx",0,REMOVE1ST,
+ "ldy","ldy",0,REMOVE1ST,
+ "ldz","ldz",0,REMOVE1ST,
+ "lda","pla",0,REMOVE1ST,
+ "lda","txa",0,REMOVE1ST,
+ "lda","tya",0,REMOVE1ST,
+ "ldx","tax",0,REMOVE1ST,
+ "ldy","tay",0,REMOVE1ST,
+ "tay","ldy",0,REMOVE1ST,
+ "taz","ldz",0,REMOVE1ST,
+ "tax","ldx",0,REMOVE1ST,
+ "txa","lda",0,REMOVE1ST,
+ "tya","lda",0,REMOVE1ST,
+ "tza","lda",0,REMOVE1ST,
+ "lda","ldx","\ttax\n",NEEDSAME,
+ "lda","ldy","\ttay\n",NEEDSAME,
+ "ldx","lda","\ttxa\n",NEEDSAME,
+ "ldy","lda","\ttya\n",NEEDSAME,
+ "sta","ldx","\ttax\n",NEEDSAME,
+ "sta","ldy","\ttay\n",NEEDSAME,
+ "stx","lda","\ttxa\n",NEEDSAME,
+ "sty","lda","\ttya\n",NEEDSAME,
+
+ };
+
+ if(nopeep) return 0;
+
+ i=emit_l;
+ if(emit_f==0)
+ entries=i-emit_f+1;
+ else
+ entries=EMIT_BUF_DEPTH;
+ asmline[0]=emit_buffer[i];
+
+ if(!strcmp(asmline[0],";startinline\n")) disabled=1;
+ if(!strcmp(asmline[0],";endinline\n")) disabled=0;
+ if(disabled) return 0;
+
+ buf1[0]=0;op1[0]=0;
+ if((j=sscanf(asmline[0]," %6s %999s",op1,buf1))>=1){
+ printf("a=%s x=%s y=%s, z=%s\n",ca,cx,cy,cz);
+ printf("\t\t%s %s\n",op1,buf1);
+ if(!strcmp(op1,"sta")) {
+ // Work out when we are accessing variables on the stack
+ if (!strcmp(buf1,"(sp),y")) {
+ // We invalidate this when Y changes
+ snprintf(ca,1024,"(sp),y",cy);
+ }
+ } else if(!strcmp(op1,"sta")){
+ // Remove writes to wherever A was loaded from
+ if (!strcmp(buf1,ca)) {
+ remove_asm();
+ return rm=1;
+ }
+ } else if(!strcmp(op1,"lda")){
+ if(buf1[0]=='#'){
+ if(!strcmp(buf1,ca)){remove_asm();return rm=1;}
+ strcpy(ca,buf1);
+ }else {
+ // Work out when we are accessing variables on the stack
+ if (!strcmp(buf1,"(sp),y")) {
+ if(!strcmp(buf1,ca)){
+ remove_asm();
+ return rm=1;
+ }
+ snprintf(ca,1024,"(sp),y",cy);
+ }
+ // Similarly look for register loads
+ // We can sometimes remove some of those, too.
+ if ((strlen(buf1)>1)&&(buf1[0]=='r')) {
+ if (strcmp(ca,buf1))
+ snprintf(ca,1024,"%s",buf1);
+ else {
+ // Don't re-load A with the same contents it already has
+ remove_asm();
+ return rm=1;
+ }
+ }
+ }
+ }else if(!strcmp(op1,"ldx")){
+ if(buf1[0]=='#'){
+ if(!rm&&!strcmp(buf1,cx)){remove_asm();return rm=1;}
+ strcpy(cx,buf1);
+ }else cx[0]=0;
+ }else if(!strcmp(op1,"ldy")){
+ if(buf1[0]=='#'){
+ if(!rm&&!strcmp(buf1,cy)){remove_asm();return rm=1;}
+ strcpy(cy,buf1);
+ }else cy[0]=0;
+ }else if(!strcmp(op1,"ldz")){
+ if(buf1[0]=='#'){
+ if(!rm&&!strcmp(buf1,cz)){remove_asm();return rm=1;}
+ strcpy(cz,buf1);
+ }else cz[0]=0;
+ }else{
+ // TODO: PGS: Add the AXYZ operations to the clobber lists.
+ // Will we need to handle them specially?
+ static char clobbernone[]="clc cld cli clv cmp cpx cpy dec inc nop pha php plp sec sed sei sta stx sty stz";
+ static char clobbera[]="adc and asl eor lsr ora pla rol ror sbc txa tya tza neg";
+ static char clobberx[]="dex inx tax tsx";
+ static char clobbery[]="dey iny tay";
+ static char clobberz[]="dez inz taz";
+ if(strstr(clobbernone,op1)){
+ // Invalidate A holding a stack variable byte if SP changes
+ if (strstr(buf1,"sp")) {
+ printf("buf1='%s'\n",buf1);
+ if (strstr(ca,"(sp),y")) ca[0]=0;
+ }
+ }else if(strstr(clobbera,op1))
+ ca[0]=0;
+ else if(strstr(clobberx,op1))
+ cx[0]=0;
+ else if(strstr(clobbery,op1)) {
+ cy[0]=0;
+ // Invalidate A holding a stack variable byte if Y changes
+ if (strstr(ca,"(sp),y")) ca[0]=0;
+ }
+ else if(strstr(clobberz,op1))
+ cz[0]=0;
+ else
+ ca[0]=cx[0]=cy[0]=cz[0]=0;
+ }
+ }else{
+ ca[0]=cx[0]=cy[0]=cz[0]=0;
+ }
+
+ rm=0;
+
+ if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"and")&&!strcmp(buf1,"#0")){
+ strcpy(asmline[0],"\tlda\t#0\n");
+ return rm=1;
+ }
+
+ if(entries>=2){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[1]=emit_buffer[i];
+
+
+ if(!strcmp(asmline[0],"; volatile barrier\n")&&!strcmp(asmline[0],asmline[1])){
+ remove_asm();
+ return rm=1;
+ }
+
+ if(sscanf(asmline[0]," %6s",op1)==1&&!strcmp(op1,"rts")&&
+ sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&!strcmp(op2,"jsr")){
+ sprintf(asmline[1],"\tjmp\t%s\n",buf2);
+ remove_asm();
+ return rm=1;
+ }
+
+ for(j=0;j<sizeof(elim)/sizeof(elim[0]);j++){
+ if(elim[j].flags&NEEDSAME){
+ if(sscanf(asmline[0]," %6s %999s",op2,buf2)==2&&
+ sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&
+ !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)&&
+ !strcmp(buf1,buf2)){
+ if(elim[j].r){
+ strcpy(asmline[0],elim[j].r);
+ }else{
+ if(elim[j].flags&REMOVE1ST)
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ }
+ return rm=1;
+ }
+ }else{
+ if(sscanf(asmline[1]," %6s",op1)==1&&
+ sscanf(asmline[0]," %6s",op2)==1&&
+ !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)){
+ if(elim[j].flags&REMOVE1ST)
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return rm=1;
+ }
+ }
+ }
+
+
+ }
+
+ if(entries>=3){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[2]=emit_buffer[i];
+ if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2){
+#if 0
+ if(!strcmp(op1,"lda")&&buf1[0]=='#'){
+ if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+ !strcmp(op2,"sta")){
+ if(sscanf(asmline[2]," %6s %999s",op2,buf2)==2&&
+ !strcmp(op2,"lda")&&!strcmp(buf1,buf2)){
+ remove_asm();
+ return rm=1;
+ }
+ }
+ }
+#endif
+ if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){
+ if(sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&
+ !strcmp(op1,"cmp")&&!strcmp(buf1,"#0")){
+ if(sscanf(asmline[2]," %6s",op1)==1&&
+ setszflag(op1)){
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return rm=1;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Return name of library function, if this node should be
+ implemented via libcall. */
+char *use_libcall(int c,int t,int t2)
+{
+ static char fname[16];
+ char *ret=0;
+
+ if(c==COMPARE){
+ if((t&NQ)==LLONG||(ISFLOAT(t)&&!ieee)){
+ sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }else{
+ t&=NU;
+ t2&=NU;
+ if(ISSHORT(t)&&c!=MULT&&c!=DIV&&c!=MOD&&!ISFLOAT(t2))
+ return 0;
+ if(ISLONG(t)&&c!=MULT&&c!=DIV&&c!=MOD&&!ISFLOAT(t2))
+ return 0;
+
+ if(!ieee&&ISFLOAT(t)) t=FLOAT;
+ if(t==LDOUBLE) t=DOUBLE;
+ if(t2==LDOUBLE) t2=DOUBLE;
+ if(!ieee&&ISFLOAT(t2)) t2=FLOAT;
+ if(c==CONVERT){
+ if(t==t2) return 0;
+ if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+ if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+
+ if(ISFLOAT(t)){
+ sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64);
+ ret=fname;
+ }
+ if(ISFLOAT(t2)){
+ sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+ if((t&NQ)==INT||(t&NQ)==LONG||(t&NQ)==LLONG||(!ieee&&ISFLOAT(t))){
+ if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+ if(t==(UNSIGNED|LLONG)&&(c==MULT||c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint64",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==LLONG){
+ sprintf(fname,"__%sint64",ename[c]);
+ ret=fname;
+ }else if(t==(UNSIGNED|LONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint32",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==LONG){
+ sprintf(fname,"__%sint32",ename[c]);
+ ret=fname;
+ }else if(t==(UNSIGNED|INT)&&(c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint16",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==INT){
+ sprintf(fname,"__%sint16",ename[c]);
+ ret=fname;
+ }else{
+ sprintf(fname,"__%s%s%s%ld",ename[c],(t&UNSIGNED)?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+int pointer_varadr(Var *v)
+{
+ int b=bank(v);
+ if(b>=0&&b!=bankcnum&&!NOBANKVARS){
+ if(cur_funcv&&bank(cur_funcv)!=b)
+ return FPOINTER;
+ }
+ return pointer_type(v->vtyp);
+}
+
+int pointer_type(struct Typ *p)
+{
+ struct Typ *merk=p;
+ if(!p) ierror(0);
+ if(LARGE) return FPOINTER;
+ while(ISARRAY(p->flags)||ISFUNC(p->flags)) p=p->next;
+ if(p->attr){
+ char *s;
+ if(strstr(p->attr,STR_HUGE)) return HPOINTER;
+ if(strstr(p->attr,STR_FAR)) return FPOINTER;
+ if(strstr(p->attr,STR_NEAR)) return POINTER;
+ }
+ return POINTER;
+}
+
+unsigned char cbmconv(unsigned char x)
+{
+ static unsigned char ctab[256]={
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x14,0x09,0x0D,0x11,0x93,0x0A,0x0E,0x0F,
+ 0x10,0x0B,0x12,0x13,0x08,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+ 0x40,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0x5B,0xBF,0x5D,0x5E,0xA4,
+ 0xAD,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0xB3,0xDD,0xAB,0xB1,0xDF,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+ 0x90,0x91,0x92,0x0C,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+ 0xA0,0xA1,0xA2,0xA3,0x5F,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0x7D,0xAC,0x60,0xAE,0xAF,
+ 0xB0,0x7E,0xB2,0x7B,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0x5C,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0xDC,0x7C,0xDE,0x7F,
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+ };
+
+ static unsigned char atab[]={0xfd,8,0x7f,0x9b,11,0x7d};
+
+ if(cbmascii)
+ return ctab[x&255];
+ else if(atascii&&x>=7&&x<=12)
+ return atab[x-7];
+ else
+ return x;
+}
+
+void insert_const(union atyps *p,int t)
+/* Traegt Konstante in entprechendes Feld ein. */
+{
+ if(!p) ierror(0);
+/* *p = (union atyps) 0 ; /* rfi: clear unused bits */
+ t&=NU;
+ if(t==CHAR) {p->vchar=vchar;return;}
+ if(t==SHORT) {p->vshort=vshort;return;}
+ if(t==INT) {p->vint=vint;return;}
+ if(t==LONG) {p->vlong=vlong;return;}
+ if(t==LLONG) {p->vllong=vllong;return;}
+ if(t==MAXINT) {p->vmax=vmax;return;}
+ if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+ if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+ if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+ if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+ if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+ if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+ if(t==FLOAT) {p->vfloat=vfloat;return;}
+ if(t==DOUBLE) {p->vdouble=vdouble;return;}
+ if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+ if(t==POINTER) {p->vuint=vuint;return;}
+ if(t==FPOINTER||t==HPOINTER) {p->vulong=vulong;return;}
+}
+
+void eval_const(union atyps *p,int t)
+/* Weist bestimmten globalen Variablen Wert einer CEXPR zu. */
+{
+ int f=t&NQ;
+ if(!p) ierror(0);
+ if(f==MAXINT||(f>=CHAR&&f<=LLONG)){
+ if(!(t&UNSIGNED)){
+ if(f==CHAR) vmax=zc2zm(p->vchar);
+ else if(f==SHORT)vmax=zs2zm(p->vshort);
+ else if(f==INT) vmax=zi2zm(p->vint);
+ else if(f==LONG) vmax=zl2zm(p->vlong);
+ else if(f==LLONG) vmax=zll2zm(p->vllong);
+ else if(f==MAXINT) vmax=p->vmax;
+ else ierror(0);
+ vumax=zm2zum(vmax);
+ vldouble=zm2zld(vmax);
+ }else{
+ if(f==CHAR) vumax=zuc2zum(p->vuchar);
+ else if(f==SHORT)vumax=zus2zum(p->vushort);
+ else if(f==INT) vumax=zui2zum(p->vuint);
+ else if(f==LONG) vumax=zul2zum(p->vulong);
+ else if(f==LLONG) vumax=zull2zum(p->vullong);
+ else if(f==MAXINT) vumax=p->vumax;
+ else ierror(0);
+ vmax=zum2zm(vumax);
+ vldouble=zum2zld(vumax);
+ }
+ }else{
+ if(ISPOINTER(f)){
+ if(f==POINTER)
+ vumax=zui2zum(p->vuint);
+ else
+ vumax=zul2zum(p->vulong);
+ vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+ }else{
+ if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+ else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+ else vldouble=p->vldouble;
+ vmax=zld2zm(vldouble);
+ vumax=zld2zum(vldouble);
+ }
+ }
+ vfloat=zld2zf(vldouble);
+ vdouble=zld2zd(vldouble);
+ vuchar=zum2zuc(vumax);
+ vushort=zum2zus(vumax);
+ vuint=zum2zui(vumax);
+ vulong=zum2zul(vumax);
+ vullong=zum2zull(vumax);
+ vchar=zm2zc(vmax);
+ vshort=zm2zs(vmax);
+ vint=zm2zi(vmax);
+ vlong=zm2zl(vmax);
+ vllong=zm2zll(vmax);
+}
+
+void printval(FILE *f,union atyps *p,int t)
+/* Gibt atyps aus. */
+{
+ t&=NU;
+ if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+ if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+ if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+ if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+ if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+ if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+ if(t==(UNSIGNED|INT)||t==POINTER){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+ if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+ if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+ if(t==MAXINT) printzm(f,p->vmax);
+ if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax);
+}
+
+void emitval(FILE *f,union atyps *p,int t)
+/* Gibt atyps aus. */
+{
+ t&=NU;
+ if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+ if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+ if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+ if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+ if(t==LDOUBLE){emitzld(f,p->vldouble);}
+ if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+ if(t==(UNSIGNED|INT)||t==POINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+ if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+ if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+ if(t==MAXINT) emitzm(f,p->vmax);
+ if(t==(UNSIGNED|MAXINT)) emitzum(f,p->vumax);
+}
+
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+ char *attr;
+ while(p){
+ if(ISPOINTER(p->flags)){
+ p->flags=((p->flags&~NU)|POINTER_TYPE(p->next));
+ if(attr=p->next->attr){
+ if(strstr(attr,STR_NEAR))
+ p->flags=((p->flags&~NU)|POINTER);
+ if(strstr(attr,STR_FAR))
+ p->flags=((p->flags&~NU)|FPOINTER);
+ if(strstr(attr,STR_HUGE))
+ p->flags=((p->flags&~NU)|HPOINTER);
+ }
+ }
+ p=p->next;
+ }
+}
+
+void add_var_hook_post(Var *v)
+{
+ if(use_sec&&(v->storage_class==STATIC||v->storage_class==EXTERN)){
+ char buf[SECLEN+32];
+ sprintf(buf,"section(\"%s\");",use_sec);
+ add_attr(&v->vattr,buf);
+ }
+ if(use_bank>=0&&(v->storage_class==STATIC||v->storage_class==EXTERN)){
+ char buf[64];
+ /*sprintf(buf,"section(\"bank%d\");bank(%d)",use_bank,use_bank);*/
+ sprintf(buf,"bank(%d)",use_bank);
+ add_attr(&v->vattr,buf);
+ }
+}
+
+int decide_reverse(zmax v)
+{
+ if(zmeqto(v,Z1)||zmeqto(v,l2zm(2L)))
+ return 1;
+ if(optspeed)
+ if(zmeqto(v,l2zm(4L))||zmeqto(v,l2zm(8L))||zmeqto(v,l2zm(256L))||zmeqto(v,l2zm(512L)))
+ return 1;
+
+ return 0;
+}
+
+static int is_single_eff_ic(struct IC *p)
+{
+ struct Var *v,*idx;
+ if(p->code!=ADDI2P||(p->typf2&NQ)!=POINTER)
+ return 0;
+ if(!(p->q2.flags&KONST)){
+ if((p->typf&NU)!=(UNSIGNED|CHAR))
+ return 0;
+ if((p->q2.flags&(VAR|DREFOBJ))!=VAR)
+ return 0;
+ if(p->q2.v->storage_class!=AUTO&&p->q2.v->storage_class!=REGISTER)
+ return 0;
+ idx=p->q2.v;
+ }else{
+ idx=0;
+ eval_const(&p->q2.val,p->typf);
+ /* TODO: more precise check considering data type useful? */
+ if(!zmleq(vumax,l2zm(255L)))
+ return 0;
+ return 1;
+ }
+ if(p->q1.flags&DREFOBJ)
+ return 0;
+ if((p->z.flags&(VAR|DREFOBJ))!=VAR)
+ return 0;
+ if(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)
+ return 0;
+ v=p->z.v;
+ for(p=p->next;p;p=p->next){
+ int c=p->code;
+ if(c==LABEL||(c>=BEQ&&c<=BRA))
+ return 1; /* TODO: how elaborate should we test? */
+ if((p->q1.flags&VAR)&&p->q1.v==v){
+ if(p->q1.flags&DREFOBJ)
+ return 1;
+ else
+ return 0;
+ }
+ if((p->q2.flags&VAR)&&p->q2.v==v){
+ if(p->q2.flags&DREFOBJ)
+ return 1;
+ else
+ return 0;
+ }
+ if((p->z.flags&VAR)&&p->z.v==v){
+ if(p->z.flags&DREFOBJ)
+ return 1;
+ else
+ return 0;
+ }
+ if((p->z.flags&VAR)&&p->z.v==idx)
+ return 0;
+ }
+ return 0;
+}
+
+void mark_eff_ics(void)
+{
+ struct IC *p;
+ for(p=first_ic;p;p=p->next){
+ if(is_single_eff_ic(p))
+ p->flags|=EFF_IC;
+ else
+ p->flags&=~EFF_IC;
+ }
+}
diff --git a/machines/m68k/machine.c b/machines/m68k/machine.c
new file mode 100644
index 0000000..3e96a31
--- /dev/null
+++ b/machines/m68k/machine.c
@@ -0,0 +1,5595 @@
+/* $VER: vbcc (m68k/machine.c) $Revision: 1.139 $ */
+/* Code generator for Motorola 680x0 CPUs. Supports 68000-68060+68881/2 */
+/* and ColdFire. */
+/* vasm, PhxAss and the GNU assembler is supported. */
+
+
+#include "supp.h"
+
+#define NEW_RET 0
+
+static char FILE_[]=__FILE__;
+
+#include "dwarf2.c"
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for m68k/ColdFire V1.15 (c) in 1995-2022 by Volker Barthelmann";
+
+/* Commandline-flags the code-generator accepts */
+int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+char *g_flags_name[MAXGF]={
+ "cpu","fpu","d2scratch","noa4","sc","sd","prof","const-in-data",
+ "use-framepointer","no-peephole","no-delayed-popping",
+ "gas","branch-opt","no-fp-return","no-mreg-return","hunkdebug",
+ "no-intz","old-peephole","conservative-sr","elf","use-commons",
+ "a2scratch","old-softfloat","amiga-softfloat","fastcall","fp2scratch",
+ "no-reserve-regs","phxass","clean-fattr","old-libcalls","vbcccall",
+ "float64"
+};
+
+union ppi g_flags_val[MAXGF];
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT of the target machine. */
+zmax char_bit;
+
+/* Sizes of all elementary types in bytes. */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. */
+char *regnames[MAXR+1]={"noreg","a0","a1","a2","a3","a4","a5","a6","a7",
+ "d0","d1","d2","d3","d4","d5","d6","d7",
+ "fp0","fp1","fp2","fp3","fp4","fp5","fp6","fp7",
+ "d0/d1","d2/d3","d4/d5","d6/d7"};
+
+static char *elfregnames[MAXR+1]={"noreg","%a0","%a1","%a2","%a3","%a4","%a5","%a6","%a7",
+ "%d0","%d1","%d2","%d3","%d4","%d5","%d6","%d7",
+ "%fp0","%fp1","%fp2","%fp3","%fp4","%fp5","%fp6","%fp7",
+ "%d0/%d1","%d2/%d3","%d4/%d5","%d6/%d7"};
+
+static char *mregnames[MAXR+1];
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* Type which can store each register. */
+type *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1]={0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1]={0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,
+ 1,0,0,0};
+
+int reg_prio[MAXR+1]={0,4,4,3,3,3,3,3,0,2,2,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0};
+
+treg_handle empty_reg_handle={0,0,0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__far","__near","__chip","__saveds",
+ "__interrupt","__amigainterrupt",0};
+#define FAR 1
+#define NEAR 2
+#define CHIP 4
+#define SAVEDS 8
+#define INTERRUPT 16
+#define AMIINTERRUPT 32
+#define STDARGS 64 /* not used, just for compatibility */
+
+int MINADDI2P=SHORT;
+
+/****************************************/
+/* Some private data and functions. */
+/****************************************/
+#define CPU (g_flags_val[0].l)
+#define FPU (g_flags_val[1].l)
+#define D2SCRATCH (g_flags[2]&USEDFLAG)
+#define NOA4 (g_flags[3]&USEDFLAG)
+#define SMALLCODE (g_flags[4]&USEDFLAG)
+#define SMALLDATA (g_flags[5]&USEDFLAG)
+#define PROFILER (g_flags[6]&USEDFLAG)
+#define CONSTINDATA (g_flags[7]&USEDFLAG)
+#define USEFRAMEPOINTER (g_flags[8]&USEDFLAG)
+#define NOPEEPHOLE (g_flags[9]&USEDFLAG)
+#define NODELAYEDPOP (g_flags[10]&USEDFLAG)
+#define GAS (g_flags[11]&USEDFLAG)
+#define BRANCHOPT (g_flags[12]&USEDFLAG)
+#define NOFPRETURN (g_flags[13]&USEDFLAG)
+#define NOMREGRETURN (g_flags[14]&USEDFLAG)
+#define HUNKDEBUG (g_flags[15]&USEDFLAG)
+#define NOINTZ (g_flags[16]&USEDFLAG)
+#define OLDPEEPHOLE (g_flags[17]&USEDFLAG)
+#define CONSERVATIVE_SR (g_flags[18]&USEDFLAG)
+#define ELF (g_flags[19]&USEDFLAG)
+#define USE_COMMONS (g_flags[20]&USEDFLAG)
+#define A2SCRATCH (g_flags[21]&USEDFLAG)
+#define OLD_SOFTFLOAT (g_flags[22]&USEDFLAG)
+#define AMI_SOFTFLOAT (g_flags[23]&USEDFLAG)
+#define FASTCALL (g_flags[24]&USEDFLAG)
+#define FP2SCRATCH (g_flags[25]&USEDFLAG)
+#define RESERVEREGS (g_flags[26]&USEDFLAG)
+#define PHXASS (g_flags[27]&USEDFLAG)
+#define CLEANFATTR (g_flags[28]&USEDFLAG)
+#define OLDLIBCALLS (g_flags[29]&USEDFLAG)
+#define VBCCCALL (g_flags[30]&USEDFLAG)
+#define FLOAT64 (g_flags[31]&USEDFLAG)
+
+
+static int use_sd;
+
+#ifdef M68K_16BIT_INT
+static long malign[MAX_TYPE+1]= {1,1,2,2,2,2,2,2,2,1,2,1,1,1,2,1};
+static long msizetab[MAX_TYPE+1]={0,1,2,2,4,8,4,8,8,0,4,0,0,0,4,0};
+#else
+static long malign[MAX_TYPE+1]= {1,1,2,2,2,2,2,2,2,1,2,1,1,1,2,1};
+static long msizetab[MAX_TYPE+1]={0,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
+#endif
+
+static type ltyp={LONG},larray={ARRAY,<yp},lltyp={LLONG};
+
+static char cpu_macro[16],fpu_macro[16],*marray[16];
+
+static char pushreglist[200],popreglist[200];
+
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define SPECIAL 3
+
+static char *labprefix,*idprefix;
+
+static int reglabel,freglabel,section=-1;
+enum {
+ a0=1,a1,a2,a3,a4,a5,a6,a7,
+ d0,d1,d2,d3,d4,d5,d6,d7,
+ fp0,fp1,fp2,fp3,fp4,fp5,fp6,fp7,
+ d0d1,d2d3,d4d5,d6d7
+};
+static int sp=8,fbp=6,framesize;
+static int stack_valid;
+static char *codename,*bssname,*dataname;
+static char *m_bssname,*m_dataname;
+static char *rprefix;
+
+static void emit_obj(FILE *,obj *,int);
+static IC *do_refs(FILE *,IC *);
+static void pr(FILE *,IC *);
+static int get_reg(FILE *,int,IC *,int);
+static long pof2(zumax);
+static void function_top(FILE *,Var *,long);
+static void function_bottom(FILE *f,Var *,long);
+
+#define saveregs(x,y) saveregswfp(x,y,0)
+static void saveregswfp(FILE *,IC *,int);
+static void restoreregsa(FILE *,IC *);
+static void restoreregsd(FILE *,IC *);
+
+static void assign(FILE *,IC *,obj *,obj *,int,long,int);
+static int compare_objects(obj *o1,obj *o2);
+
+static char x_s[]={'0','b','w','3','l'};
+#ifdef M68K_16BIT_INT
+static char x_t[]={'?','b','w','w','l','L','s','d','d','v','l','a','s','u','e','f'};
+#else
+static char x_t[]={'?','b','w','l','l','L','s','d','d','v','l','a','s','u','e','f'};
+#endif
+
+static char *quick[2]={"","q"};
+static char *strshort[2]={"l","w"};
+
+static char *ubranch[]={"eq","ne","cs","cc","ls","hi"};
+
+static int pushedreg,stored_cc; /* pushedreg&2: aregsaved; 4: dreg; 8: freg */
+ /* 16: durch RESTOREREGS gepushed */
+static int comptyp;
+static int pushflag;
+static int geta4;
+static int dscratch=1,ascratch=1,fscratch=1;
+
+#define D16OFF 1024
+
+static int newobj=0; /* um zu erkennen, ob neue section erlaubt ist */
+
+static int cf;
+static int add_stdargs;
+
+static int isquickkonst(union atyps *,int),isquickkonst2(union atyps *,int),regavailable(int);
+static void move(FILE *,obj *,int,obj *,int,int);
+static void loadext(FILE *,int,obj *,int);
+static void add(FILE *,obj *,int,obj *,int,int);
+static void sub(FILE *,obj *,int,obj *,int,int);
+static void mult(FILE *,obj *,int,obj *,int,int,int,IC *);
+
+extern int static_cse;
+
+static void scratch_modified(void)
+{
+ BSET(regs_modified,a0);
+ BSET(regs_modified,a1);
+ BSET(regs_modified,d0);
+ BSET(regs_modified,d1);
+ if(FPU>68000){
+ BSET(regs_modified,fp0);
+ BSET(regs_modified,fp1);
+ }
+ if(D2SCRATCH) BSET(regs_modified,d2);
+ if(A2SCRATCH) BSET(regs_modified,a2);
+ if(FP2SCRATCH) BSET(regs_modified,fp2);
+
+}
+
+static long pof2(zumax x)
+/* Yields log2(x)+1 oder 0. */
+{
+ zumax p;int ln=1;
+ p=ul2zum(1UL);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+#ifdef M68K_16BIT_INT
+#define ISHWORD(x) ((x&NQ)<=INT)
+#else
+#define ISHWORD(x) ((x&NQ)<INT)
+#endif
+
+#define PEA -1
+#define LEA -2
+
+#define FUNCPREFIX(t) ((stdargs(t)&&rparmtype!=PARMVBCC)?idprefix:(rparmtype==PARMVBCC?"@$":"@"))
+
+static void emit_lword(FILE *,obj *);
+static void emit_hword(FILE *,obj *);
+static int addressing(IC *);
+static long notpopped,dontpop,stackoffset,loff,maxpushed,stack;
+static int offlabel,regoffset;
+/* For keeping track of condition codes. */
+static obj *cc_set,*cc_set_tst;
+static int cc_typ,cc_typ_tst;
+static int missing,savedemit,savedalloc;
+static int lastpush,unorderedpush,pushoff[MAXR+1];
+
+static int vsec(FILE *f,Var *v)
+{
+ char *type="bss";
+ if(!sec_per_obj||(v->tattr&CHIP)) return 0;
+ if(ISFUNC(v->vtyp->flags)||(v->clist&&is_const(v->vtyp))) type="code"; else if(v->clist) type="data";
+ emit(f,"\t%ssection\t\"DONTMERGE_%s.%s.%ld\"%s%s\n",GAS?".":"",type,v->identifier,v->storage_class==STATIC/*&&!ISFUNC(v->vtyp->flags)*/?(long)zm2l(v->offset):0L,GAS?"":",",GAS?"":type);
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+static int special_section(FILE *f,Var *v)
+{
+ char *sec;
+ if(!v->vattr) return vsec(f,v);;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return vsec(f,v);;
+ sec+=strlen("section(");
+ if(GAS)
+ emit(f,"\t.section\t");
+ else
+ emit(f,"\tsection\t");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+static enum{
+ PARMSTD,
+ PARMVBCC,
+ PARMSAS
+} rparmtype;
+
+static int stdargs(type *t)
+{
+ type *p;
+
+ if(VBCCCALL) rparmtype=PARMVBCC;
+ else if(FASTCALL) rparmtype=PARMSAS;
+ else rparmtype=PARMSTD;
+
+ for(p=t->next;p;p=p->next){
+ if(p->attr&&strstr(p->attr,"__stdargs")) {rparmtype=PARMSTD;return 1;}
+ if(p->attr&&strstr(p->attr,"__vbccargs")) {rparmtype=PARMVBCC;return 0;}
+ if(p->attr&&strstr(p->attr,"__regargs")) {rparmtype=PARMSAS;return 0;}
+ if(CLEANFATTR) break;
+ }
+ if((!FASTCALL&&!VBCCCALL)||add_stdargs) return 1;
+ if(t->flags==FUNKT&&is_varargs(t)) return 1;
+ return 0;
+}
+
+/* pushed on the stack by a callee, no pop needed */
+static void callee_push(long l)
+{
+ if(l-stackoffset>stack)
+ stack=l-stackoffset;
+}
+static void push(long l)
+{
+ stackoffset-=l;
+ if(stackoffset<maxpushed)
+ maxpushed=stackoffset;
+ if(-maxpushed>stack)
+ stack=-maxpushed;
+}
+static void pop(long l)
+{
+ stackoffset+=l;
+}
+
+void title(FILE *f)
+{
+ static int done;
+ extern char *inname; /*grmpf*/
+ if(!done&&f){
+ done=1;
+ if(GAS)
+ emit(f,"\t.file\t\"%s\"\n",inname);
+ else
+ emit(f,"\tidnt\t\"%s\"\n",inname);
+ }
+}
+
+static int is_arg_reg(IC *p,int r)
+{
+ int i,u;IC *a;
+ for(i=0;i<p->arg_cnt;i++){
+ a=p->arg_list[i];
+ u=0;
+ if((a->z.flags&(REG|DREFOBJ))==REG)
+ u=a->z.reg;
+ else if((a->z.flags&VAR)&&a->z.v->reg)
+ u=a->z.v->reg;
+ if(u){
+ if(r==u||(reg_pair(u,&rp)&&r==rp.r1||r==rp.r2)){
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int am_uses_reg(IC *p,int i)
+{
+ if((p->q1.am&&((p->q1.am->dreg&127)==i||p->q1.am->basereg==i))
+ ||(p->q2.am&&((p->q2.am->dreg&127)==i||p->q2.am->basereg==i))
+ ||(p->z.am&&((p->z.am->dreg&127)==i||p->z.am->basereg==i)))
+ return 1;
+ return 0;
+}
+
+/* check if register can be scratched */
+static int scratchreg(int r,IC *p)
+{
+ int c;
+ while(1){
+ p=p->next;
+ if(!p||((c=p->code)==FREEREG&&p->q1.reg==r)) return 1;
+ if(c==CALL||(c>=BEQ&&c<=BRA)) return 0;
+ if((p->q1.flags®)&&p->q1.reg==r) return 0;
+ if((p->q2.flags®)&&p->q2.reg==r) return 0;
+ if((p->z.flags®)&&p->z.reg==r) return 0;
+ if(am_uses_reg(p,r)) return 0;
+ }
+}
+
+
+
+static int pget_reg(FILE *f,int flag,IC *p,int useq1)
+{
+ int i;
+
+ flag=1+flag*8;
+
+ if(useq1){
+ if(isreg(q1)&&p->q1.reg>=flag&&p->q1.reg<=flag+7&&scratchreg(p->q1.reg,p))
+ return p->q1.reg;
+ }
+
+ for(i=flag;i<flag+8;i++){
+ if(regs[i]==1&&(!p||(i!=p->q1.reg&&i!=p->q2.reg&&i!=p->z.reg))){
+ if(p){
+ if(am_uses_reg(p,i))
+ continue;
+ if(p->code==CALL&&is_arg_reg(p,i))
+ continue;
+ }
+ regs[i]|=8;
+ pushflag=1;
+ emit(f,"\tmove.l\t%s,%ld(%s)\n",mregnames[i],-stackoffset,mregnames[sp]);
+ if(i<d0)
+ pushedreg|=2;
+ else if (i<fp0)
+ pushedreg|=4;
+ else
+ pushedreg|=8;
+ BSET(regs_modified,i);
+ return i;
+ }
+ }
+ ierror(0);
+}
+
+static int get_reg(FILE *f,int flag,IC *p,int useq1)
+/* Gets a register: flag=0=areg, 1=dreg, 2=fpreg */
+{
+ int i;
+
+ flag=1+flag*8;
+
+ if(useq1){
+ if(isreg(q1)&&p->q1.reg>=flag&&p->q1.reg<=flag+7&&scratchreg(p->q1.reg,p))
+ return p->q1.reg;
+ }
+
+ for(i=flag;i<flag+8;i++){
+ if(regs[i]==0){
+ if(p){
+ if(am_uses_reg(p,i))
+ continue;
+ if(p->code==CALL&&is_arg_reg(p,i))
+ continue;
+ }
+ regs[i]=2;pushedreg|=1;
+ if(!regused[i]&&!regscratch[i]){regused[i]=1; }
+ BSET(regs_modified,i);
+ return i;
+ }
+ }
+ for(i=flag;i<flag+8;i++){
+ static rpair rp;
+ if(regs[i]==1){
+ if(p){
+ if((p->q1.am&&((p->q1.am->dreg&127)==i||p->q1.am->basereg==i))
+ ||(p->q2.am&&((p->q2.am->dreg&127)==i||p->q2.am->basereg==i))
+ ||(p->z.am&&((p->z.am->dreg&127)==i||p->z.am->basereg==i))){
+ continue;
+ }
+ if(p->code==CALL&&is_arg_reg(p,i))
+ continue;
+ if(p->q1.flags®){
+ if(p->q1.reg==i) continue;
+ if(reg_pair(p->q1.reg,&rp)&&(rp.r1==i||rp.r2==i)) continue;
+ }
+ if(p->q2.flags®){
+ if(p->q2.reg==i) continue;
+ if(reg_pair(p->q2.reg,&rp)&&(rp.r1==i||rp.r2==i)) continue;
+ }
+ if(p->z.flags®){
+ if(p->z.reg==i) continue;
+ if(reg_pair(p->z.reg,&rp)&&(rp.r1==i||rp.r2==i)) continue;
+ }
+ }
+ regs[i]+=4;
+ if(i<lastpush){
+ unorderedpush=1;
+ /*printf("%s %s\n",mregnames[lastpush],mregnames[i]);*/
+ }
+ if(i<fp0){
+ emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[i],mregnames[sp]);
+ push(4);
+ pushoff[i]=pushoff[lastpush]+4;
+ }else{
+ emit(f,"\tfmove.x\t%s,-(%s)\n",mregnames[i],mregnames[sp]);
+ push(12);
+ pushoff[i]=pushoff[lastpush]+12;
+ }
+ lastpush=i;
+ if(i<d0)
+ pushedreg|=2;
+ else if(i<fp0)
+ pushedreg|=4;
+ else
+ pushedreg|=8;
+ BSET(regs_modified,i);
+ return i;
+ }
+ }
+ ierror(0);
+}
+static int isquickkonst(union atyps *p,int t)
+/* Returns 1 if constant is between -128 and 127. */
+{
+ zmax zm;zumax zum;
+ if(ISFLOAT(t)) return 0;
+ eval_const(p,t);
+ if(t&UNSIGNED){
+ zum=ul2zum(127UL);
+ return zumleq(vumax,zum);
+ }else{
+ zm=l2zm(-129L);
+ if(zmleq(vmax,zm)) return 0;
+ zm=l2zm(127L);
+ return zmleq(vmax,zm);
+ }
+}
+static int isquickkonst2(union atyps *p,int t)
+/* Returns 1 if constant is between 1 and 8. */
+{
+ zmax zm;zumax zum;
+ if(ISFLOAT(t)) return 0;
+ eval_const(p,t);
+ if(t&UNSIGNED){
+ if(zumeqto(ul2zum(0UL),vumax)) return 0;
+ zum=ul2zum(8UL);
+ return zumleq(vumax,zum);
+ }else{
+ if(zmeqto(l2zm(0L),vmax)) return 0;
+ zm=l2zm(-1L);
+ if(zmleq(vmax,zm)) return 0;
+ zm=l2zm(8L);
+ return zmleq(vmax,zm);
+ }
+}
+
+static int pregavailable(IC *p,int art)
+/* Returns true if matching register is available. Handles arglist*/
+{
+ int i;
+ art=1+art*8;
+ for(i=art+1;i<art+8;i++)
+ if(regs[i]==0&&!is_arg_reg(p,i)) return(1);
+ return 0;
+}
+
+static int regavailable(int art)
+/* Returns true if matching register is available. */
+{
+ int i;
+ art=1+art*8;
+ for(i=art+1;i<art+8;i++)
+ if(regs[i]==0) return(1);
+ return 0;
+}
+static int compare_objects(obj *o1,obj *o2)
+/* Tests if two objects are equal. */
+{
+ if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
+ return 1;
+ if((o1->flags&(KONST|VAR|DREFOBJ|REG|VARADR))==(o2->flags&(KONST|VAR|DREFOBJ|REG|VARADR))&&o1->am==o2->am){
+ if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+ if(!(o1->flags®)||o1->reg==o2->reg){
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+static IC *do_refs(FILE *f,IC *p)
+/* Loads DREFOBJs into address registers, if necessary. */
+/* Small constants are loaded into data registers if this */
+/* improves code. */
+{
+ int reg,c=p->code,t=p->typf,equal;
+ if((p->q1.flags&DREFOBJ)&&!(p->q1.flags&KONST)&&(!(p->q1.flags®)||p->q1.reg<1||p->q1.reg>8)){
+ equal=0;
+ if(compare_objects(&p->q1,&p->q2)) equal|=1;
+ if(compare_objects(&p->q1,&p->z)) equal|=2;
+ if(p->code==PUSH&&!pregavailable(p,0))
+ reg=pget_reg(f,0,p,0);
+ else if(p->code==CALL&&!pregavailable(p,0))
+ return p;
+ else
+ reg=get_reg(f,0,p,0);
+ p->q1.flags&=~DREFOBJ;
+ emit(f,"\tmove.l\t");emit_obj(f,&p->q1,POINTER);
+ p->q1.flags=REG|DREFOBJ;
+ p->q1.reg=reg;
+ emit(f,",%s\n",mregnames[p->q1.reg]);
+ if(equal&1) p->q2=p->q1;
+ if(equal&2) p->z=p->q1;
+ if(c==TEST) cc_set_tst=cc_set=0;
+ }
+ if((p->q2.flags&DREFOBJ)&&!(p->q2.flags&KONST)&&(!(p->q2.flags®)||p->q2.reg<1||p->q2.reg>8)){
+ if(compare_objects(&p->q2,&p->z)) equal=1; else equal=0;
+ reg=get_reg(f,0,p,0);
+ p->q2.flags&=~DREFOBJ;
+ emit(f,"\tmove.l\t");emit_obj(f,&p->q2,POINTER);
+ p->q2.flags=REG|DREFOBJ;
+ p->q2.reg=reg;
+ emit(f,",%s\n",mregnames[p->q2.reg]);
+ if(equal) p->z=p->q2;
+ }
+ if((p->z.flags&DREFOBJ)&&!(p->z.flags&KONST)&&(!(p->z.flags®)||p->z.reg<1||p->z.reg>8)){
+ reg=get_reg(f,0,p,0);
+ p->z.flags&=~DREFOBJ;
+ emit(f,"\tmove.l\t");emit_obj(f,&p->z,POINTER);
+ p->z.flags=REG|DREFOBJ;
+ p->z.reg=reg;
+ emit(f,",%s\n",mregnames[p->z.reg]);
+ }
+ if(CPU!=68040){
+ /* Don't do it on 040 because it's slower. */
+ if(x_t[t&NQ]=='l'&&(t&NQ)!=FLOAT&&(c!=ASSIGN||!isreg(z))&&
+ c!=MULT&&c!=DIV&&c!=MOD&&c!=LSHIFT&&c!=RSHIFT&&c!=SETRETURN&&c!=PUSH&&c!=ADDI2P&&c!=SUBIFP&&
+ (!(p->z.flags®)||p->z.reg<d0||p->z.reg>d7)){
+ /* Constants into registers. */
+ if(isconst(q1)&&isquickkonst(&p->q1.val,t)&&((c!=ADD&&c!=SUB&&c!=ADDI2P&&c!=SUBIFP)||!isquickkonst2(&p->q1.val,t))){
+ eval_const(&p->q1.val,t);
+ if((!zldeqto(d2zld(0.0),vldouble)||!zmeqto(l2zm(0L),vmax)||!zumeqto(ul2zum(0UL),vumax))&®available(1)){
+ reg=get_reg(f,1,p,0);
+ move(f,&p->q1,0,0,reg,t);
+ p->q1.flags=REG;p->q1.reg=reg;
+ p->q1.val.vmax=l2zm(0L);
+ }
+ }
+ if(isconst(q2)&&isquickkonst(&p->q2.val,t)&&((c!=ADD&&c!=SUB&&c!=ADDI2P&&c!=SUBIFP)||!isquickkonst2(&p->q2.val,t))){
+ eval_const(&p->q2.val,t);
+ if((!zldeqto(d2zld(0.0),vldouble)||!zmeqto(l2zm(0L),vmax)||!zumeqto(ul2zum(0UL),vumax))&®available(1)){
+ reg=get_reg(f,1,p,0);
+ move(f,&p->q2,0,0,reg,t);
+ p->q2.flags=REG;p->q2.reg=reg;
+ p->q2.val.vmax=l2zm(0L);
+ }
+ }
+ }
+ }
+ return p;
+}
+static void pr(FILE *f,IC *p)
+/* Release registers and pop them from stack if necessary. */
+{
+ int i,size=0;char *s="";
+ /* To keep track of condition codes. */
+#if 0
+ if((pushedreg&12)&&(p->code==TEST||p->code==COMPARE)){
+ char *fp;IC *branch;
+ if(FPU>68000&&ISFLOAT(p->typf)) fp="f"; else fp="";
+ branch=p;
+ while(branch->code<BEQ||branch->code>=BRA) branch=branch->next;
+ /*FIXME*/
+ if((p->typf&UNSIGNED)||ISPOINTER(p->typf)){
+ emit(f,"\ts%s\t-2(%s)\n",ubranch[branch->code-BEQ],mregnames[sp]);
+ }else{
+ emit(f,"\t%ss%s\t-2(%s)\n",fp,ename[branch->code]+1,mregnames[sp]);
+ }
+ stored_cc=1;
+ }
+#endif
+ if((pushedreg&12)&&(p->code==TEST||p->code==COMPARE||p->code==SETRETURN)){
+ s="m";
+ if(!GAS&&!PHXASS) emit(f,"\topt\tom-\n");
+ }
+ for(i=MAXR;i>0;i--){
+ if(regs[i]==2) regs[i]=0;
+ if(regs[i]&8){
+ regs[i]&=~8;
+
+ emit(f,"\tmove%s.l\t%ld(%s),%s\n",s,-stackoffset,mregnames[sp],mregnames[i]);
+ if(i>=d0) cc_set=0;
+ if(cc_set&&(cc_set->flags®)&&cc_set->reg==i)
+ cc_set=0;
+ missing++;
+ }
+ if(regs[i]&4){
+ regs[i]&=~4;
+ if(i>=1&&i<=d7){
+ if(unorderedpush)
+ emit(f,"\tmove%s.l\t%d(%s),%s\n",s,pushoff[lastpush]-pushoff[i],mregnames[sp],mregnames[i]);
+ else{
+ if(cf&&*s=='m'){
+ emit(f,"\tmove%s.l\t(%s),%s\n\taddq.l\t#4,%s\n",s,mregnames[sp],mregnames[i],mregnames[sp]);
+ }else{
+ emit(f,"\tmove%s.l\t(%s)+,%s\n",s,mregnames[sp],mregnames[i]);
+ }
+ }
+ pop(4);size+=4;
+ }else if(i>=fp0&&i<=fp7){
+ if(unorderedpush)
+ emit(f,"\tfmove%s.x\t%d(%s),%s\n",s,pushoff[lastpush]-pushoff[i],mregnames[sp],mregnames[i]);
+ else
+ emit(f,"\tfmove%s.x\t(%s)+,%s\n",s,mregnames[sp],mregnames[i]);
+ pop(12);size+=12;
+ }else if(i>=25&&i<=28){
+ if(unorderedpush)
+ emit(f,"\tmovem.l\t%d(%s),%s\n",pushoff[lastpush]-pushoff[i],mregnames[sp],mregnames[i]);
+ else{
+ if(cf)
+ emit(f,"\tmovem.l\t(%s),%s\n\taddq.l\t#8,%s\n",mregnames[sp],mregnames[i],mregnames[sp]);
+ else
+ emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],mregnames[i]);
+ }
+ pop(8);size+=8;
+ }else
+ ierror(0);
+ if(i>=d0) cc_set=0;
+ if(cc_set&&(cc_set->flags®)&&cc_set->reg==i)
+ cc_set=0;
+ missing++;
+ }
+ }
+ if(*s=='m'&&!GAS&&!PHXASS) emit(f,"\topt\tom+\n");
+#if 0
+ if((pushedreg&12)&&(p->code==TEST||p->code==COMPARE))
+ emit(f,"\ttst.b\t-%d(%s)\n",size+2,mregnames[sp]);
+#endif
+ if(unorderedpush)
+ emit(f,"\tadd%s.%c\t#%d,%s\n",pushoff[lastpush]<=8?"q":"",cf?'l':'w',pushoff[lastpush],mregnames[sp]);
+ lastpush=0;
+ unorderedpush=0;
+}
+static void emit_obj(FILE *f,obj *p,int t)
+/* Write object. */
+{
+ if(p->am){
+ /* Addressing modes. */
+ if(NOPEEPHOLE) {ierror(0);p->am=0;return;}
+ if(p->am->skal>=0){
+ long l=0;
+ if(p->flags&D16OFF) l=zm2l(p->val.vmax);
+ emit(f,"(%ld",p->am->dist+l);
+ if(!GAS&&CPU>=68020&&((p->am->dist+l)>32767||(p->am->dist+l)<-32768))
+ emit(f,".l");
+ else if(!GAS&&CPU>=68020&&((p->am->dist+l)>127||(p->am->dist+l)<-128))
+ emit(f,".w");
+ emit(f,",%s",mregnames[p->am->basereg]);
+ if(p->am->dreg){
+ emit(f,",%s",mregnames[p->am->dreg&127]);
+ if(p->am->dreg&128) emit(f,".w"); else emit(f,".l");
+ if(p->am->skal) emit(f,"*%d",p->am->skal);
+ }
+ emit(f,")");
+ return;
+ }
+ if((p->flags&D16OFF)&&p->am->skal<0&&!zmeqto(l2zm(0L),p->val.vmax)) ierror(0);
+ if(p->am->skal==-1){
+ emit(f,"(%s)+",mregnames[p->am->basereg]);
+ return;
+ }
+ if(p->am->skal==-2){ /* Noch nicht implementiert */
+ emit(f,"-(%s)",mregnames[p->am->basereg]);
+ return;
+ }
+ }
+ if(p->flags&DREFOBJ){
+ if(p->flags&KONST){
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ emit(f,"(");
+ if((p->flags&D16OFF)&&!zmeqto(l2zm(0L),p->val.vmax)){
+ emitval(f,&p->val,MAXINT);
+ if(!zmleq(p->val.vmax,l2zm(32767L))||!zmleq(l2zm(-32768L),p->val.vmax))
+ emit(f,".l");
+ else if(!zmleq(p->val.vmax,l2zm(127L))||!zmleq(l2zm(-128L),p->val.vmax))
+ emit(f,".w");
+ emit(f,",");
+ }
+ }
+ if(p->flags&VARADR) emit(f,"#");
+ if(p->flags&VAR) {
+ if(p->flags®){
+ emit(f,"%s",mregnames[p->reg]);
+ }else if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+ long os;
+ os=zm2l(p->val.vmax);
+ if(!USEFRAMEPOINTER&&!vlas){
+ if(!zmleq(l2zm(0L),p->v->offset))
+ os=os+loff-zm2l(p->v->offset)+(PROFILER?16:0);
+ else
+ os=os+zm2l(p->v->offset);
+ if(!GAS&&CPU>=68020&&(os-stackoffset)>0x7c00) /* +l%d max.1024? */
+ emit(f,"((%ld+%s%d).l,%s)",os-stackoffset,labprefix,offlabel,mregnames[sp]);
+ else
+ emit(f,"(%ld+%s%d,%s)",os-stackoffset,labprefix,offlabel,mregnames[sp]);
+ }else{
+ if(!zmleq(l2zm(0L),p->v->offset))
+ os=os-zm2l(p->v->offset)+4+(PROFILER?16:0);
+ else
+ os=os-(zm2l(p->v->offset)+zm2l(szof(p->v->vtyp)));
+ emit(f,"(%ld",os);
+ if(!GAS&&CPU>=68020&&os>0x7fff)
+ emit(f,".l");
+ emit(f,",%s)",mregnames[fbp]);
+ }
+ }else{
+ if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,MAXINT);emit(f,"+");}
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ if(ISFUNC(p->v->vtyp->flags))
+ emit(f,"%s%s",FUNCPREFIX(p->v->vtyp),p->v->identifier);
+ else
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ if(use_sd&&!(p->flags&VARADR)&&!ISFUNC(p->v->vtyp->flags)
+ &&!(p->v->tattr&(CHIP|FAR))&&(CONSTINDATA||!is_const(p->v->vtyp))
+ &&zmleq(l2zm(0L),p->val.vmax)&&!zmleq(szof(p->v->vtyp),p->val.vmax))
+ emit(f,"(a4)");
+ }
+ }
+ if((p->flags®)&&!(p->flags&VAR)) emit(f,"%s",mregnames[p->reg]);
+ if(p->flags&KONST){
+ /* This requires IEEE floats/doubles on the host compiler. */
+ if(ISFLOAT(t)){
+ unsigned char *ip=(unsigned char *)&p->val.vfloat;
+ char *s;
+ if(GAS) s="0x"; else s="$";
+ emit(f,"#%s%02x%02x%02x%02x",s,ip[0],ip[1],ip[2],ip[3]);
+ if((t&NQ)!=FLOAT){
+ if(DEBUG&1) printf("doubleconst=%f\n",zld2d(zd2zld(p->val.vdouble)));
+ emit(f,"%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ }else{
+ emit(f,"#");emitval(f,&p->val,t&NU);
+ }
+ }
+ if(p->flags&DREFOBJ) emit(f,")");
+}
+static void dwarf2_print_frame_location(FILE *f,Var *v)
+{
+ /*FIXME: needs a location list and correct register trabslation */
+ obj o;
+ o.flags=REG;
+ if(USEFRAMEPOINTER||vlas)
+ o.reg=fbp;
+ else
+ o.reg=sp;
+ o.val.vmax=l2zm(0L);
+ o.v=0;
+ dwarf2_print_location(f,&o);
+}
+static int dwarf2_regnumber(int r)
+{
+ if(r<=8)
+ return r+7;
+ else if(r<=d7)
+ return r-8;
+ else if(r<=fp7)
+ return r+1;
+ else
+ ierror(0);
+}
+static zmax dwarf2_fboffset(Var *v)
+{
+ long os;
+ if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0);
+ if(!USEFRAMEPOINTER&&!vlas){
+ if(!zmleq(l2zm(0L),v->offset))
+ os=loff-zm2l(v->offset);
+ else
+ os=zm2l(v->offset);
+ return l2zm(os+framesize);
+ }else{
+ if(!zmleq(l2zm(0L),v->offset))
+ return l2zm(-zm2l(v->offset)+4);
+ else
+ return l2zm(-(zm2l(v->offset)+zm2l(szof(v->vtyp))));
+ }
+}
+
+static char tsh[]={'w','l'};
+static int proflabel,stacksizelabel;
+static void function_top(FILE *f,Var *v,long offset)
+/* Writes function header. */
+{
+ geta4=0;
+ if(GAS){
+ }else{
+ if(debug_info&&HUNKDEBUG) emit(f,"\tsymdebug\n");
+ if(CPU!=68000) emit(f,"\tmachine\t%ld\n",CPU);
+ if(cf) strshort[1]="l";
+ if(FPU>68000) emit(f,"\tfpu\t1\n");
+ if(SMALLCODE) emit(f,"\tnear\tcode\n");
+ if(use_sd) emit(f,"\tnear\ta4,-2\n");
+ if(PHXASS){
+ emit(f,"\topt\t0\n\topt\tNQLPSM");
+ if(CPU!=68040) emit(f,"R");
+ if(1/*BRANCHOPT||(optflags&2)*/) emit(f,"BT");
+ emit(f,"\n");
+ }else{
+ emit(f,"\topt o+,ol+,op+,oc+,ot+,oj+,ob+,om+");
+ if(CPU==68040) emit(f,",a-");
+ emit(f,"\n");
+ }
+ }
+ if(!special_section(f,v)&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(PROFILER){
+ proflabel=++label;
+ if(GAS){
+ emit(f,"%s%d:\n\t.byte\t\"%s\",0\n",labprefix,proflabel,v->identifier);
+ }else{
+ emit(f,"%s%d\n\tdc.b\t\"%s\",0\n",labprefix,proflabel,v->identifier);
+ }
+ }
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC){
+ if(GAS){
+ emit(f,"\t.global\t%s%s\n",FUNCPREFIX(v->vtyp),v->identifier);
+ }else{
+ emit(f,"\tpublic\t%s%s\n",FUNCPREFIX(v->vtyp),v->identifier);
+ }
+ }
+ }
+ if(v->storage_class==EXTERN){
+ if(GAS){
+ emit(f,"\t.align\t4\n%s%s:\n",FUNCPREFIX(v->vtyp),v->identifier);
+ }else{
+ emit(f,"\tcnop\t0,4\n%s%s\n",FUNCPREFIX(v->vtyp),v->identifier);
+ }
+ }else{
+ if(GAS){
+ emit(f,"\t.align\t4\n%s%ld:\n",labprefix,zm2l(v->offset));
+ }else{
+ emit(f,"\tcnop\t0,4\n%s%ld\n",labprefix,zm2l(v->offset));
+ }
+ }
+ if(stack_check&&!(v->tattr&AMIINTERRUPT)){
+ stacksizelabel=++label;
+ if(GAS){
+ emit(f,"\tmove.l\t#%s%d,-(%s)\n\tjbsr\t___stack_check\n\taddq.l\t#4,%s\n",labprefix,stacksizelabel,mregnames[sp],mregnames[sp]);
+ }else{
+ emit(f,"\tmove.l\t#%s%d,-(%s)\n\tjsr\t___stack_check\n\taddq.l\t#4,%s\n",labprefix,stacksizelabel,mregnames[sp],mregnames[sp]);
+ }
+ }
+ if(PROFILER){
+ if(GAS){
+ emit(f,"\tsub.l\t#16,%s\n\tmove.l\t%s,-(%s)\n\tpea\t%s%d\n\t.global\t__startprof\n\tjbsr\t__startprof\n\taddq.%s\t#8,%s\n",mregnames[sp],mregnames[sp],mregnames[sp],labprefix,proflabel,strshort[1],mregnames[sp]);
+ }else{
+ emit(f,"\tsub.l\t#16,%s\n\tmove.l\t%s,-(%s)\n\tpea\t%s%d\n\tpublic\t__startprof\n\tjsr\t__startprof\n\taddq.%s\t#8,%s\n",mregnames[sp],mregnames[sp],mregnames[sp],labprefix,proflabel,strshort[1],mregnames[sp]);
+ }
+ }
+ offset=-((offset+4-1)/4)*4;
+ loff=-offset;offlabel=++label;
+ if(!USEFRAMEPOINTER&&!vlas){
+ if(offset<0) emit(f,"\tsub%s.%s\t#%ld,%s\n",quick[offset>=-8],strshort[offset>=-32768],-offset,mregnames[sp]);
+ }else{
+ if(offset>=-32768||CPU>=68020){
+ emit(f,"\tlink.%c\t%s,#%ld\n",tsh[offset<-32768],mregnames[fbp],offset);
+ }else{
+ emit(f,"\tlink.w\t%s,#-32768\n",mregnames[fbp]);offset+=32768;
+ emit(f,"\tsub.%c\t#%ld,%s\n",tsh[offset<-32768],offset,mregnames[fbp]);
+ }
+ }
+ if(FPU>68000&&float_used){
+ if(GAS){
+ emit(f,"\t.word\t0xf227,%s%d\n",labprefix,freglabel);
+ }else{
+ emit(f,"\tfmovem.x\t%s%d,-(%s)\n",labprefix,freglabel,mregnames[sp]);
+ }
+ }
+ if(cf){
+ emit(f,"\tsub.l\t#%s%d,%s\n",labprefix,offlabel,mregnames[sp]);
+ if(GAS){
+ emit(f,"\tmovem.l\t#%s%d,(%s)\n",labprefix,reglabel,mregnames[sp]);
+ }else{
+ emit(f,"\tmovem.l\t%s%d,(%s)\n",labprefix,reglabel,mregnames[sp]);
+ }
+ }else{
+ if(GAS){
+ emit(f,"\tmovem.l\t#%s%d,-(%s)\n",labprefix,reglabel,mregnames[sp]);
+ }else{
+ emit(f,"\tmovem.l\t%s%d,-(%s)\n",labprefix,reglabel,mregnames[sp]);
+ }
+ }
+ if((v->tattr&SAVEDS)&&use_sd) emit(f,"\txref\t_LinkerDB\n\tlea\t_LinkerDB,a4\n");
+ stack_valid=1;
+ stack=0;
+}
+static void function_bottom(FILE *f,Var *v,long offset)
+/* Writes function footer. */
+{
+ int i,size=0;unsigned int pushval,popval;
+ *pushreglist=0;*popreglist=0;
+ pushval=popval=0;
+ if((v->tattr&SAVEDS)&&use_sd) geta4=1;
+ for(i=1;i<=16;i++){
+ if((((regused[i]&&!regscratch[i])||((v->tattr&INTERRUPT)&&BTST(regs_modified,i)))&&!regsa[i])||(i==5&&geta4)||(i==d0&&pushflag)){
+ if(*pushreglist) strcat(pushreglist,"/");
+ strcat(pushreglist,mregnames[i]);
+ if(i!=d0||(v->tattr&INTERRUPT)){
+ if(*popreglist) strcat(popreglist,"/");
+ strcat(popreglist,mregnames[i]);
+ }
+ if(i<d0){
+ pushval|=(256>>i);popval|=(128<<i);
+ }else{
+ pushval|=(0x8000>>(i-9));
+ if(i!=d0) popval|=(1<<(i-9));
+ }
+ size+=4;
+ }
+ }
+ if(pushflag){
+ emit(f,"\taddq.%c\t#4,%s\n",cf?'l':'w',mregnames[sp]);
+ if(v->tattr&INTERRUPT) ierror(0);
+ }
+ if(cf){
+ if(GAS){
+ if(popval)
+ emit(f,"\t.equ\t%s%d,%u\n\tmovem.l\t(%s),#%u\n\tadd.l\t#%s%d%s,%s\n",labprefix,reglabel,pushval,mregnames[sp],popval,labprefix,offlabel,pushflag?"-4":"",mregnames[sp]);
+ else
+ emit(f,"\t.equ\t%s%d,0\n",labprefix,reglabel);
+ }else{
+ if(*pushreglist)
+ emit(f,"%s%d\treg\t%s\n",labprefix,reglabel,pushreglist);
+ else
+ emit(f,"%s%d\treg\n",labprefix,reglabel);
+ if(*popreglist)
+ emit(f,"\tmovem.l\t(%s),%s\n\tadd.l\t#%s%d%s,%s\n",mregnames[sp],popreglist,labprefix,offlabel,pushflag?"-4":"",mregnames[sp]);
+ }
+ }else{
+ if(GAS){
+ if(popval)
+ emit(f,"\t.equ\t%s%d,%u\n\tmovem.l\t(%s)+,#%u\n",labprefix,reglabel,pushval,mregnames[sp],popval);
+ else
+ emit(f,"\t.equ\t%s%d,0\n",labprefix,reglabel);
+ }else{
+ if(*pushreglist)
+ emit(f,"%s%d\treg\t%s\n",labprefix,reglabel,pushreglist);
+ else
+ emit(f,"%s%d\treg\n",labprefix,reglabel);
+ if(*popreglist)
+ emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],popreglist);
+ }
+ }
+ *pushreglist=0;*popreglist=0;pushval=0xe000;popval=0xd000;
+ for(i=fp0;i<=fp7;i++){
+ if((((regused[i]&&!regscratch[i])||((v->tattr&INTERRUPT)&&BTST(regs_modified,i)))&&!regsa[i])){
+ if(*popreglist) strcat(popreglist,"/");
+ strcat(popreglist,mregnames[i]);
+ pushval|=(1<<(i-17));popval|=(0x80>>(i-17));
+ size+=12;
+ }
+ }
+ if(FPU>68000&&(float_used||(v->tattr&INTERRUPT))){
+ if(GAS){
+ if(popval!=0xd000)
+ emit(f,"\t.equ\t%s%d,0x%x\n\t.word\t0xf21f,0x%x\n",labprefix,freglabel,(int)pushval,(int)popval);
+ else
+ emit(f,"\t.equ\t%s%d,0xe000\n",labprefix,freglabel);
+ }else{
+ if(*popreglist)
+ emit(f,"%s%d\tfreg\t%s\n\tfmovem.x\t(%s)+,%s%d\n",labprefix,freglabel,popreglist,mregnames[sp],labprefix,freglabel);
+ else
+ emit(f,"%s%d\tfreg\n",labprefix,freglabel);
+ }
+ }
+ if(cf||(!USEFRAMEPOINTER&&!vlas)){
+ if(GAS){
+ emit(f,"\t.equ\t%s%d,%d\n",labprefix,offlabel,size);
+ }else{
+ emit(f,"%s%d\tequ\t%d\n",labprefix,offlabel,size);
+ }
+ }
+ if(!USEFRAMEPOINTER&&!vlas){
+ if(loff) emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[loff<=8],strshort[loff<32768],loff,mregnames[sp]);
+ framesize=size;
+ }else
+ emit(f,"\tunlk\t%s\n",mregnames[fbp]);
+ if(PROFILER){
+ if(GAS){
+ emit(f,"\tmove.l\t%s,-(%s)\n\t.global\t__endprof\n\tjbsr\t__endprof\n\tadd.%s\t#20,%s\n",mregnames[sp],mregnames[sp],strshort[1],mregnames[sp]);
+ }else{
+ emit(f,"\tmove.l\t%s,-(%s)\n\tpublic\t__endprof\n\tjsr\t__endprof\n\tadd.%s\t#20,%s\n",mregnames[sp],mregnames[sp],strshort[1],mregnames[sp]);
+ }
+ }
+ if(v->tattr&INTERRUPT)
+ emit(f,"\trte\n");
+ else
+ emit(f,"\trts\n");
+ if(stack_check&&!(v->tattr&AMIINTERRUPT)){
+ if(GAS)
+ emit(f,"\t.equ\t%s%d,%ld\n",labprefix,stacksizelabel,size+loff-maxpushed);
+ else
+ emit(f,"%s%d\tequ\t%ld\n",labprefix,stacksizelabel,size+loff-maxpushed);
+ }
+ if(stack_valid){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=l2zm(size+loff+stack);
+ emit(f,"%c stacksize=%ld\n",GAS?'#':';',size+loff+stack);
+ }
+}
+static void move(FILE *f,obj *q,int qreg,obj *z,int zreg,int t)
+/* erzeugt eine move Anweisung...Da sollen mal Optimierungen rein */
+{
+ if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg;
+ if(!qreg&&(q->flags&(REG|DREFOBJ))==REG) qreg=q->reg;
+ if(zreg==qreg&&zreg) return;
+ if(q&&(q->flags&VARADR)&&zreg>=1&&zreg<=8){
+ emit(f,"\tlea\t");
+ q->flags&=~VARADR;emit_obj(f,q,t);q->flags|=VARADR;
+ emit(f,",%s\n",mregnames[zreg]);
+ BSET(regs_modified,zreg);
+ return;
+ }
+ if(zreg>=d0&&zreg<fp0&&q&&(q->flags&(KONST|DREFOBJ))==KONST&&isquickkonst(&q->val,t)){
+ emit(f,"\tmoveq\t");
+ }else{
+ if((zreg>=fp0&&zreg<=fp7)||(qreg>=fp0&&qreg<=fp7)){
+ if(qreg>=fp0&&qreg<=fp7&&zreg>=fp0&&zreg<=fp7) emit(f,"\tfmove.x\t");
+ else emit(f,"\tfmove.%c\t",x_t[t&NQ]);
+ }else{
+ if(!cf||qreg||zreg)
+ emit(f,"\tmove.%c\t",x_s[msizetab[t&NQ]]);
+ }
+ }
+ if(cf&&!qreg&&!zreg){
+ static IC dummy;
+ dummy.code=ASSIGN;
+ dummy.typf=t;
+ dummy.q1=*q;
+ dummy.q2.flags=0;
+ dummy.z=*z;
+ qreg=get_reg(f,1,&dummy,0);
+ emit(f,"\tmove.%c\t",x_s[msizetab[t&NQ]]);
+ emit_obj(f,q,t);
+ emit(f,",%s\n\tmove.%c\t%s,",mregnames[qreg],x_s[msizetab[t&NQ]],mregnames[qreg]);
+ emit_obj(f,z,t);
+ emit(f,"\n");
+ }else{
+ if(qreg) emit(f,"%s",mregnames[qreg]); else emit_obj(f,q,t);
+ emit(f,",");
+ if(zreg) emit(f,"%s",mregnames[zreg]); else emit_obj(f,z,t);
+ emit(f,"\n");
+ if(zreg) BSET(regs_modified,zreg);
+ }
+}
+static void loadext(FILE *f,int r,obj *q,int t)
+/* laedt Objekt q vom Typ t in Register r und erweitert auf long */
+{
+ if(t&UNSIGNED){
+ if((q->flags&(REG|DREFOBJ))==REG&&q->reg==r)
+ emit(f,"\tand.l\t#%u,%s\n",((t&NQ)==CHAR?0xffu:0xffffu),mregnames[r]);
+ else
+ emit(f,"\tmoveq\t#0,%s\n",mregnames[r]);
+ }
+ move(f,q,0,0,r,t);
+#ifdef M68K_16BIT_INT
+ if((t&NU)==SHORT||(t&NU)==INT) emit(f,"\text.l\t%s\n",mregnames[r]);
+#else
+ if((t&NU)==SHORT) emit(f,"\text.l\t%s\n",mregnames[r]);
+#endif
+ if((t&NU)==CHAR){
+ if(cf||CPU>=68020)
+ emit(f,"\textb.l\t%s\n",mregnames[r]);
+ else
+ emit(f,"\text.w\t%s\n\text.l\t%s\n",mregnames[r],mregnames[r]);
+ }
+}
+
+static void add(FILE *f,obj *q,int qreg,obj *z,int zreg,int t)
+/* erzeugt eine add Anweisung...Da sollen mal Optimierungen rein */
+{
+ if(!qreg&&!q) ierror(0);
+ if(!zreg&&!z) ierror(0);
+ if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg;
+ if(cf&&x_t[t&NQ]!='l'&&(qreg||(q->flags&(KONST|DREFOBJ))!=KONST)) ierror(0);
+ if(!qreg&&(q->flags&(KONST|DREFOBJ))==KONST&&isquickkonst2(&q->val,t)){
+ emit(f,"\taddq.%c\t",cf?'l':x_t[t&NQ]);
+ }else{
+ /* hier noch Abfrage, ob #c.w,ax */
+ emit(f,"\tadd.%c\t",cf?'l':x_t[t&NQ]);
+ }
+ if(qreg) emit(f,"%s",mregnames[qreg]); else emit_obj(f,q,t);
+ emit(f,",");
+ if(zreg) emit(f,"%s",mregnames[zreg]); else emit_obj(f,z,t);
+ emit(f,"\n");
+}
+static void sub(FILE *f,obj *q,int qreg,obj *z,int zreg,int t)
+/* erzeugt eine sub Anweisung...Da sollen mal Optimierungen rein */
+{
+ if(cf&&x_t[t&NQ]!='l'&&(qreg||(q->flags&(KONST|DREFOBJ))!=KONST)) ierror(0);
+ if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg;
+ if(q&&(q->flags&(KONST|DREFOBJ))==KONST&&isquickkonst2(&q->val,t)){
+ emit(f,"\tsubq.%c\t",cf?'l':x_t[t&NQ]);
+ }else{
+ /* hier noch Abfrage, ob #c.w,ax */
+ emit(f,"\tsub.%c\t",cf?'l':x_t[t&NQ]);
+ }
+ if(qreg) emit(f,"%s",mregnames[qreg]); else emit_obj(f,q,t);
+ emit(f,",");
+ if(zreg) emit(f,"%s",mregnames[zreg]); else emit_obj(f,z,t);
+ emit(f,"\n");
+}
+static void mult(FILE *f,obj *q,int qreg,obj *z,int zreg, int t,int c,IC *p)
+/* erzeugt eine mult Anweisung...Da sollen mal Optimierungen rein */
+/* erzeugt auch div/mod etc. */
+{
+ int modreg;
+ if(!qreg&&(q->flags&(REG|DREFOBJ))==REG) qreg=q->reg;
+ if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg;
+ if(cf&&!qreg) {qreg=get_reg(f,1,p,0);move(f,q,0,0,qreg,t);}
+ if((c==MULT||c==DIV||c==MOD)&&CPU<68020&&!cf&&msizetab[t&NQ]==4){
+ if(c==MULT){
+ /* ist das mit get_reg(.,.,0) ok? nochmal ueberdenken... */
+ /* ...die ganze Routine am besten... */
+ /* ...es war nicht, deshalb ist es jetzt geaendert */
+ int dx,dy,t1,t2;
+ if(zreg>=d0&&zreg<=d7){
+ dx=zreg;
+ }else{
+ dx=get_reg(f,1,p,0);
+ move(f,z,0,0,dx,t);
+ }
+ if(qreg>=d0&&qreg<=d7&&qreg!=dx){
+ dy=qreg;
+ }else{
+ dy=get_reg(f,1,p,0);
+ move(f,q,0,0,dy,t);
+ }
+ t1=get_reg(f,1,p,0);t2=get_reg(f,1,p,0);
+ if(t1==dx||t2==dx||t1==dy||t2==dy) ierror(0);
+ emit(f,"\tmove.l\t%s,%s\n",mregnames[dx],mregnames[t1]);
+ emit(f,"\tmove.l\t%s,%s\n",mregnames[dy],mregnames[t2]);
+ emit(f,"\tswap\t%s\n",mregnames[t1]);
+ emit(f,"\tswap\t%s\n",mregnames[t2]);
+ emit(f,"\tmulu.w\t%s,%s\n",mregnames[dy],mregnames[t1]);
+ emit(f,"\tmulu.w\t%s,%s\n",mregnames[dx],mregnames[t2]);
+ emit(f,"\tmulu.w\t%s,%s\n",mregnames[dy],mregnames[dx]);
+ emit(f,"\tadd.w\t%s,%s\n",mregnames[t2],mregnames[t1]);
+ emit(f,"\tswap\t%s\n",mregnames[t1]);
+ emit(f,"\tclr.w\t%s\n",mregnames[t1]);
+ emit(f,"\tadd.l\t%s,%s\n",mregnames[t1],mregnames[dx]);
+ if(zreg!=dx) move(f,0,t1,z,0,t);
+ }else ierror(0);
+ return;
+ }
+ if(c==MULT){
+ /* das duerfte nur der Aesthetik dienen... */
+ if(t&UNSIGNED)
+ emit(f,"\tmulu.%c\t",x_t[t&NQ]);
+ else
+ emit(f,"\tmuls.%c\t",x_t[t&NQ]);
+ if((t&NQ)<=SHORT) cc_set=0;
+ }
+ if(c==DIV||(c==MOD&&ISHWORD(t))){
+ if(t&UNSIGNED){
+ if(ISHWORD(t)) emit(f,"\tand.l\t#65535,%s\n",mregnames[zreg]);
+ emit(f,"\tdivu.%c\t",x_t[t&NQ]);
+ }else{
+ if(ISHWORD(t)) emit(f,"\text.l\t%s\n",mregnames[zreg]);
+ emit(f,"\tdivs.%c\t",x_t[t&NQ]);
+ }
+ }
+ if(qreg)
+ emit(f,"%s",mregnames[qreg]);
+ else
+ emit_obj(f,q,t);
+ emit(f,",");
+ /* eigentlich muss zreg!=0 sein... */
+ if(zreg)
+ emit(f,"%s",mregnames[zreg]);
+ else
+ emit_obj(f,z,t);
+ emit(f,"\n");
+ if(c==MOD){
+ emit(f,"\tswap\t%s\n",mregnames[zreg]);
+ cc_set=0;
+ }
+}
+static IC *am_freedreg[9],*am_shiftdreg[9];
+static IC *am_dist_ic[9],*am_dreg_ic[9],*am_use[9];
+/* am_dist_ic und am_dreg_ic werden auch fuer (ax)+ benutzt */
+static long am_dist[9],am_dreg[9],am_base[9],am_inc[9],am_skal[9],am_dbase[9];
+#define AMS sizeof(AddressingMode)
+
+static int mopsize(IC *p,int reg)
+/* Liefert die Groesse in Bytes, mit der im IC auf (reg) zugegriffen wird. */
+{
+ int c=p->code;
+ if(c==ADDI2P||c==SUBIFP){
+ if((p->q2.flags®)&&p->q2.reg==reg)
+ return zm2l(sizetab[p->typf&NQ]);
+ return 4;
+ }
+ if(c==CONVERT){
+ if((p->z.flags®)&&p->z.reg==reg)
+ return zm2l(sizetab[p->typf&NQ]);
+ else
+ return zm2l(sizetab[p->typf2&NQ]);
+ }
+ return zm2l(sizetab[p->typf&NQ]);
+}
+static void clear_am(int reg)
+/* loescht Werte fuer erweiterte Adressierungsarten fuer Register reg */
+{
+ if(reg<0||reg>d7) ierror(0);
+ if(DEBUG&32) printf("clear_am(%s)\n",mregnames[reg]);
+ if(reg<=8){
+ am_dist_ic[reg]=am_dreg_ic[reg]=am_use[reg]=0;
+ am_dist[reg]=am_dreg[reg]=am_base[reg]=am_inc[reg]=0;
+ }else{
+ reg-=8;
+ am_freedreg[reg]=am_shiftdreg[reg]=0;
+ am_skal[reg]=am_dbase[reg]=0;
+ }
+}
+static void mod_reg(int r)
+{
+ int i;
+ for(i=1;i<=8;i++){
+ if((!am_use[i]&&am_base[i]==r)||(am_dreg[i]&127)==r)
+ clear_am(i);
+ }
+#if 0
+ if(r>=9&&r<=16){
+ for(i=9;i<=16;i++){
+ if(am_dbase[i-8]==r)
+ clear_am(i);
+ }
+ }
+#endif
+}
+/* return non-zero if IC is implemented by a function call */
+static int islibcall(IC *p)
+{
+ int c=p->code,t=p->typf/NQ;
+ if((c==DIV||c==MOD)&&CPU<68020)
+ return 1;
+ if(t==LLONG&&c!=ADD&&c!=SUB&&c!=OR&&c!=AND&&c!=XOR&&c!=COMPARE)
+ return 1;
+ if(ISFLOAT(t)&&FPU<=68000)
+ return 1;
+ if(c==CONVERT){
+ if(t==LLONG||ISFLOAT(t))
+ return 1;
+ t=p->typf2&NQ;
+ if(t==LLONG||ISFLOAT(t))
+ return 1;
+ }
+ return 0;
+}
+
+static int new_peephole(IC *first)
+{
+ int localused=0,c,r,t,c2;long sz;
+ IC *p,*p2;
+ AddressingMode *am;
+ for(p=first;p;p=p->next){
+ int c=p->code;
+ if(!localused){
+ if((p->q1.flags&(VAR|REG))==VAR&&(p->q1.v->storage_class==AUTO||p->q1.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q1.v->offset))
+ localused=1;
+ if((p->q2.flags&(VAR|REG))==VAR&&(p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q2.v->offset))
+ localused=1;
+ if((p->z.flags&(VAR|REG))==VAR&&(p->z.v->storage_class==AUTO||p->z.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->z.v->offset))
+ localused=1;
+ if(DEBUG&32&&localused==1) printf("localused=1\n");
+ }
+ /* -(ax) */
+ if(c==SUBIFP&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg&&p->q1.reg<=8&&isconst(q2)){
+ r=p->q1.reg;
+ eval_const(&p->q2.val,q2typ(p));
+ sz=zm2l(vmax);
+ if(sz==1||sz==2||sz==4||sz==8){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r&&(!(p2->q2.flags®)||p2->q2.reg!=r)&&(!(p2->z.flags®)||p2->z.reg!=r)&&(c2!=CONVERT||(q1typ(p2)&NQ)<=(ztyp(p2)&NQ))){
+ t=(q1typ(p2)&NQ);
+ if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[q1typ(p2)&NQ],l2zm(sz))&&!islibcall(p2)){
+ p2->q1.am=am=mymalloc(sizeof(*am));
+ p2->q1.val.vmax=l2zm(0L);
+ am->basereg=r;
+ am->dist=0;
+ am->skal=-2;
+ am->dreg=0;
+ p->code=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ break;
+ }
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r&&(!(p2->q1.flags®)||p2->q1.reg!=r)&&(!(p2->z.flags®)||p2->z.reg!=r)){
+ t=(q2typ(p2)&NQ);
+ if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[q2typ(p2)&NQ],l2zm(sz))&&!islibcall(p2)){
+ p2->q2.am=am=mymalloc(sizeof(*am));
+ p2->q2.val.vmax=l2zm(0L);
+ am->basereg=r;
+ am->dist=0;
+ am->skal=-2;
+ am->dreg=0;
+ p->code=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ break;
+ }
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r&&(!(p2->q2.flags®)||p2->q2.reg!=r)&&(!(p2->q1.flags®)||p2->q1.reg!=r)){
+ t=(ztyp(p2)&NQ);
+ if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[ztyp(p2)&NQ],l2zm(sz))&&!islibcall(p2)){
+ p2->z.am=am=mymalloc(sizeof(*am));
+ p2->z.val.vmax=l2zm(0L);
+ am->basereg=r;
+ am->dist=0;
+ am->skal=-2;
+ am->dreg=0;
+ p->code=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ break;
+ }
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if((p2->q1.flags®)&&p2->q1.reg==r) break;
+ if((p2->q2.flags®)&&p2->q2.reg==r) break;
+ if((p2->z.flags®)&&p2->z.reg==r) break;
+ }
+ }
+ }
+ /* (ax)+ in q1 */
+ if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q1.reg<=8&&(c!=CONVERT||(q1typ(p)&NQ)<=(ztyp(p)&NQ))){
+ t=(q1typ(p)&NQ);
+ sz=zm2l(sizetab[t]);
+ r=p->q1.reg;
+ if((sz==1||sz==2||sz==4||sz==8)&&(ISINT(t)||ISPOINTER(t))&&t!=LLONG&&(!(p->q2.flags®)||p->q2.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)&&(!p->q2.am||p->q2.am->basereg!=r)&&(!p->z.am||p->z.am->basereg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST&&!islibcall(p)){
+ eval_const(&p2->q2.val,q2typ(p2));
+ if(zmeqto(vmax,l2zm(sz))){
+ p->q1.am=am=mymalloc(sizeof(*am));
+ p->q1.val.vmax=l2zm(0L);
+ am->basereg=r;
+ am->dist=0;
+ am->skal=-1;
+ am->dreg=0;
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ break;
+ }
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if((p2->q1.flags®)&&p2->q1.reg==r) break;
+ if((p2->q2.flags®)&&p2->q2.reg==r) break;
+ if((p2->z.flags®)&&p2->z.reg==r) break;
+ if(p2->q1.am&&p2->q1.am->basereg==r) break;
+ if(p2->q2.am&&p2->q2.am->basereg==r) break;
+ if(p2->z.am&&p2->z.am->basereg==r) break;
+ }
+ }
+ }
+ /* (ax)+ in q2 */
+ if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg<=8){
+ t=(q2typ(p)&NQ);
+ sz=zm2l(sizetab[t]);
+ r=p->q2.reg;
+ if((sz==1||sz==2||sz==4||sz==8)&&(ISINT(t)||ISPOINTER(t))&&t!=LLONG&&(!(p->q1.flags®)||p->q1.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)&&(!p->q1.am||p->q1.am->basereg!=r)&&(!p->z.am||p->z.am->basereg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST&&!islibcall(p)){
+ eval_const(&p2->q2.val,q2typ(p2));
+ if(zmeqto(vmax,l2zm(sz))){
+ p->q2.am=am=mymalloc(sizeof(*am));
+ p->q2.val.vmax=l2zm(0L);
+ am->basereg=r;
+ am->dist=0;
+ am->skal=-1;
+ am->dreg=0;
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ break;
+ }
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if((p2->q1.flags®)&&p2->q1.reg==r) break;
+ if((p2->q2.flags®)&&p2->q2.reg==r) break;
+ if((p2->z.flags®)&&p2->z.reg==r) break;
+ if(p2->q1.am&&p2->q1.am->basereg==r) break;
+ if(p2->q2.am&&p2->q2.am->basereg==r) break;
+ if(p2->z.am&&p2->z.am->basereg==r) break;
+ }
+ }
+ }
+ /* (ax)+ in z */
+ if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->z.reg<=8){
+ t=(ztyp(p)&NQ);
+ sz=zm2l(sizetab[t]);
+ r=p->z.reg;
+ if((sz==1||sz==2||sz==4||sz==8)&&(ISINT(t)||ISPOINTER(t))&&t!=LLONG&&(!(p->q1.flags®)||p->q1.reg!=r)&&(!(p->q2.flags®)||p->q2.reg!=r)&&(!p->q2.am||p->q2.am->basereg!=r)&&(!p->q1.am||p->q1.am->basereg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST&&!islibcall(p)){
+ eval_const(&p2->q2.val,q2typ(p2));
+ if(zmeqto(vmax,l2zm(sz))){
+ p->z.am=am=mymalloc(sizeof(*am));
+ p->z.val.vmax=l2zm(0L);
+ am->basereg=r;
+ am->dist=0;
+ am->skal=-1;
+ am->dreg=0;
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ break;
+ }
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if((p2->q1.flags®)&&p2->q1.reg==r) break;
+ if((p2->q2.flags®)&&p2->q2.reg==r) break;
+ if((p2->z.flags®)&&p2->z.reg==r) break;
+ if(p2->q1.am&&p2->q1.am->basereg==r) break;
+ if(p2->q2.am&&p2->q2.am->basereg==r) break;
+ if(p2->z.am&&p2->z.am->basereg==r) break;
+ }
+ }
+ }
+ /* d(ax) (+d(ax,dy)) */
+ if((c==ADDI2P||c==SUBIFP)&&isreg(z)&&p->z.reg<=8&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+ int base,idx=-1;zmax of;obj *o;
+ IC *idx_ic=0,*free_idx=0,*free_base=0,*use=0;
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ if(CPU>=68020||(zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L)))){
+ r=p->z.reg;
+ if(isreg(q1)&&p->q1.reg<=8) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(!idx_ic&&c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg>=d0&&p2->q2.reg<fp0){
+ if(CPU>=68020||(zmleq(of,l2zm(127L))&&zmleq(l2zm(-128L),of))){
+ idx=p2->q2.reg;
+ idx_ic=p2;
+ continue;
+ }
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(!use&&idx_ic&&c2==FREEREG&&p2->q1.reg==idx){
+ free_idx=p2;
+ continue;
+ }
+ if(!use&&c2==FREEREG&&p2->q1.reg==base){
+ free_base=p2;
+ continue;
+ }
+ if(idx_ic){
+ if((p2->q1.flags®)&&p2->q1.reg==idx) break;
+ if((p2->q2.flags®)&&p2->q2.reg==idx) break;
+ if((p2->z.flags®)&&p2->z.reg==idx) break;
+ if(p2->q1.am&&(p2->q1.am->dreg&127)==idx) break;
+ if(p2->q2.am&&(p2->q2.am->dreg&127)==idx) break;
+ if(p2->z.am&&(p2->z.am->dreg&127)==idx) break;
+ if(c2==ALLOCREG&&p2->q1.reg==idx) break;
+ }
+
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&c2==PUSH){
+ if(o) break;
+ o=&p2->q1;
+ use=p2;
+ continue;
+ }
+
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o) break;
+ o=&p2->q1;
+ use=p2;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o) break;
+ o=&p2->q2;
+ use=p2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+
+ if(o) break;
+ if(p2->z.flags&&(idx==d0||idx==d1)&&FPU<=68000&&ISFLOAT(ztyp(p2))&&!(p2->q2.flags==0&&c2!=CONVERT)) break;
+ o=&p2->z;
+ use=p2;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ o->val.vmax=l2zm(0L);
+ am->basereg=base;
+ am->dist=zm2l(of);
+ am->skal=0;
+ if(free_base) move_IC(use,free_base);
+ if(idx_ic){
+ am->dreg=idx;
+ if(ISHWORD(idx_ic->typf)) am->dreg|=128;
+ if(free_idx) move_IC(use,free_idx);
+ idx_ic->code=NOP;
+ idx_ic->q1.flags=idx_ic->q2.flags=idx_ic->z.flags=0;
+ }else
+ am->dreg=0;
+ if(isreg(q1)&&p->q1.reg<=8){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ if(!(o->flags&DREFOBJ)){
+ o->flags|=DREFOBJ;
+ if(use->code==PUSH)
+ use->code=PEA;
+ else if(use->code==ASSIGN)
+ use->code=LEA;
+ else
+ ierror(0);
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+ /* (ax,dy) (+d(ax,dy)) */
+ if(c==ADDI2P&&isreg(q2)&&p->q2.reg>=d0&&isreg(z)&&p->z.reg<=8&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+ int base,idx;obj *o;
+ long dist=0;
+ IC *free_idx=0,*free_base=0,*use=0,*off=0;
+ r=p->z.reg;idx=p->q2.reg;
+ if(isreg(q1)&&p->q1.reg<=8) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(!off&&(c2==ADDI2P||c2==SUBIFP)&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,p2->typf);
+ if(c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+ if(CPU>=68020||(zmleq(vmax,l2zm(127L))&&zmleq(l2zm(-128L),vmax))){
+ dist=zm2l(vmax);
+ off=p2;
+ continue;
+ }
+ }
+
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+
+
+
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&c2==PUSH){
+ if(o) break;
+
+ o=&p2->q1;
+ use=p2;
+ continue;
+ }
+
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+ if(c2==ALLOCREG&&(p->q1.reg==idx||p->q1.reg==base)) break;
+ if(!use&&c2==FREEREG&&p2->q1.reg==base) free_base=p2;
+ if(!use&&c2==FREEREG&&p2->q1.reg==idx) free_idx=p2;
+
+
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||(q1typ(p2)&NQ)==LLONG) break;
+ o=&p2->q1;use=p2;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||(q2typ(p2)&NQ)==LLONG) break;
+ o=&p2->q2;use=p2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||(ztyp(p2)&NQ)==LLONG) break;
+ if(p2->z.flags&&(idx==d0||idx==d1)&&FPU<=68000&&ISFLOAT(ztyp(p2))&&!(p2->q2.flags==0&&c2!=CONVERT)) break;
+
+ o=&p2->z;use=p2;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ /* do not use addressing mode for libcalls */
+ if(FPU<=68000&&o&&o==&use->z&&(ISFLOAT(use->typf)||ISFLOAT(use->typf2))&&use->code!=ASSIGN)
+ break;
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ o->val.vmax=l2zm(0L);
+ am->basereg=base;
+ am->dreg=idx;
+ am->dist=dist;
+ am->skal=0;
+ if(ISHWORD(q2typ(p))) am->dreg|=128;
+ if(isreg(q1)&&p->q1.reg<=8){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ if(off){
+ off->code=NOP;
+ off->q1.flags=off->q2.flags=off->z.flags=0;
+ }
+ if(!use) ierror(0);
+ if(free_idx) move_IC(use,free_idx);
+ if(free_base) move_IC(use,free_base);
+ if(free_idx&&use->next!=free_idx&&use->next->next!=free_idx) ierror(0);
+ if(free_base&&use->next!=free_base&&use->next->next!=free_base) ierror(0);
+ if(!(o->flags&DREFOBJ)){
+ o->flags|=DREFOBJ;
+ if(use->code==PUSH)
+ use->code=PEA;
+ else if(use->code==ASSIGN)
+ use->code=LEA;
+ else
+ ierror(0);
+ }
+ }
+
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+
+
+ }
+
+ /* do an additional pass to search for scaled addressing-modes */
+ if(CPU>=68020){
+ for(p=first;p;p=p->next){
+ c=p->code;t=p->typf;
+ if((c==MULT||c==LSHIFT)&&isconst(q2)&&isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&ISINT(t)&&(t&NQ)<=LONG){
+ unsigned long ul;
+ r=p->z.reg;
+ eval_const(&p->q2.val,q2typ(p));
+ ul=zum2ul(vumax);
+ if(c==LSHIFT){
+ if(ul<=3)
+ ul=1<<ul;
+ else
+ ul=0;
+ }
+ if(ul==2||ul==4||ul==8){
+ AddressingMode *amuse=0;
+ IC *free_src=0,*free_rsrc=0,*use=0;
+ int src_mod=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(!use&&p2->q1.am&&p2->q1.am->skal==0&&(p2->q1.am->dreg&127)==r&&(!p2->q2.am||(p2->q2.am->dreg&127)!=r)&&(!p2->z.am||(p2->z.am->dreg&127)!=r)&&(!(p2->q2.flags®)||p2->q2.flags!=r)&&(!(p2->z.flags®)||p2->z.flags!=r)){
+ amuse=p2->q1.am;
+ use=p2;
+ continue;
+ }
+ if(!use&&p2->q2.am&&p2->q2.am->skal==0&&(p2->q2.am->dreg&127)==r&&(!p2->q1.am||(p2->q1.am->dreg&127)!=r)&&(!p2->z.am||(p2->z.am->dreg&127)!=r)&&(!(p2->q1.flags®)||p2->q1.flags!=r)&&(!(p2->z.flags®)||p2->z.flags!=r)){
+ amuse=p2->q2.am;
+ use=p2;
+ continue;
+ }
+ if(!use&&p2->z.am&&p2->z.am->skal==0&&(p2->z.am->dreg&127)==r&&(!p2->q2.am||(p2->q2.am->dreg&127)!=r)&&(!p2->q1.am||(p2->q1.am->dreg&127)!=r)&&(!(p2->q2.flags®)||p2->q2.flags!=r)&&(!(p2->z.flags®)||p2->z.flags!=r)){
+ amuse=p2->z.am;
+ use=p2;
+ continue;
+ }
+ if(!use&&c2==FREEREG&&p2->q1.reg==r){
+ free_src=p2;
+ continue;
+ }
+ if(!use&&c2==FREEREG&&isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7&&p2->q1.reg==p->q1.reg){
+ free_rsrc=p2;
+ continue;
+ }
+ if(use&&((c2==FREEREG&&p2->q1.reg==r)||((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r))){
+ amuse->skal=ul;
+ if(!src_mod&&isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7){
+ amuse->dreg=p->q1.reg;
+ p->code=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=ASSIGN;
+ p->q2.flags=0;
+ p->q2.val.vmax=sizetab[p->typf&NQ];
+ }
+ if(free_src) move_IC(use,free_src);
+ if(free_rsrc) move_IC(use,free_rsrc);
+ break;
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if((p2->q1.flags®)&&p2->q1.reg==r) break;
+ if((p2->q2.flags®)&&p2->q2.reg==r) break;
+ if((p2->z.flags®)&&p2->z.reg==r) break;
+ if(p2->q1.am&&(p2->q1.am->dreg&127)==r) break;
+ if(p2->q2.am&&(p2->q2.am->dreg&127)==r) break;
+ if(p2->z.am&&(p2->z.am->dreg&127)==r) break;
+ if((p2->z.flags&(REG|DREFOBJ))==REG&&(p->q1.flags&(REG|DREFOBJ))&&p2->z.reg==p->q1.reg)
+ src_mod=1;
+ }
+ }
+ }
+ }
+ }
+
+ /* another pass to remove unnecessary ALLOCREGs */
+ for(p=first;p;p=p->next){
+ if(p->code==ALLOCREG){
+ r=p->q1.reg;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==ALLOCREG&&p2->q1.reg==r) ierror(0);
+ if(c2==FREEREG&&p2->q1.reg==r){
+ p->code=NOP;
+ p->q1.flags=0;
+ p2->code=NOP;
+ p2->q1.flags=0;
+ savedalloc++;
+ break;
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if((p2->q1.flags®)&&p2->q1.reg==r) break;
+ if((p2->q2.flags®)&&p2->q2.reg==r) break;
+ if((p2->z.flags®)&&p2->z.reg==r) break;
+ if((am=p2->q1.am)&&(am->basereg==r||(am->dreg&127)==r)) break;
+ if((am=p2->q2.am)&&(am->basereg==r||(am->dreg&127)==r)) break;
+ if((am=p2->z.am)&&(am->basereg==r||(am->dreg&127)==r)) break;
+ }
+ }
+ }
+
+ return localused;
+}
+static int addressing(IC *p)
+/* Untersucht ICs auf erweiterte Addresierungsarten */
+{
+ int count,localused=0;
+ if(!OLDPEEPHOLE) return new_peephole(p);
+ if(DEBUG&32) printf("addressing() started\n");
+ for(count=1;count<=16;count++) clear_am(count);
+ for(count=0;p;p=p->next){
+ int c=p->code,q1reg,q2reg,zreg;
+ if(p->q1.flags®) q1reg=p->q1.reg; else q1reg=0;
+ if(p->q2.flags®) q2reg=p->q2.reg; else q2reg=0;
+ if(p->z.flags®) zreg=p->z.reg; else zreg=0;
+ if(c==ADDI2P) c=ADD;
+ if(c==SUBIFP) c=SUB;
+ if(DEBUG&32) pric2(stdout,p);
+ if(!localused){
+ if((p->q1.flags&(VAR|REG))==VAR&&(p->q1.v->storage_class==AUTO||p->q1.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q1.v->offset))
+ localused=1;
+ if((p->q2.flags&(VAR|REG))==VAR&&(p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q2.v->offset))
+ localused=1;
+ if((p->z.flags&(VAR|REG))==VAR&&(p->z.v->storage_class==AUTO||p->z.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->z.v->offset))
+ localused=1;
+ if(DEBUG&32&&localused==1) printf("localused=1\n");
+ }
+ if(c==ASSIGN&&isreg(q1)&&isreg(z)&&q1reg>=1&&q1reg<=8&&zreg>=1&&zreg<=8){
+ /* fuer (ax)+ */
+ int i;
+ clear_am(q1reg);
+ for(i=1;i<=8;i++)
+ if(am_base[i]==zreg||am_base[i]==q1reg) clear_am(i);
+ mod_reg(zreg);
+ clear_am(zreg);am_base[zreg]=q1reg;am_dreg_ic[zreg]=p;
+ if(DEBUG&32) printf("move %s,%s found\n",mregnames[q1reg],mregnames[zreg]);
+ continue;
+ }
+ if(c==MULT&&CPU>=68020&&isconst(q2)&&isreg(z)&&zreg>=d0&&zreg<=d7){
+ /* dx=a*const, fuer Skalierung */
+ int dreg=zreg-8;
+ if(dreg<1||dreg>8) ierror(0);
+ if(q1reg>=1&&q1reg<=d7){
+ if(isreg(q1)&&(q1reg>8||am_use[q1reg]!=p)) clear_am(q1reg);
+ if((p->q1.flags&DREFOBJ)&&q1reg<=8&&am_use[q1reg]) clear_am(q1reg);
+ }
+ if(DEBUG&32) printf("mult x,const->dreg found\n");
+ mod_reg(zreg);
+ if(am_skal[dreg]) {clear_am(zreg);continue;}
+ eval_const(&p->q2.val,p->typf);
+ am_skal[dreg]=zm2l(vmax);
+ if(am_skal[dreg]!=2&&am_skal[dreg]!=4&&am_skal[dreg]!=8)
+ {clear_am(zreg);continue;}
+ am_shiftdreg[dreg]=p;
+ if(isreg(q1)&&q1reg>=d0&&q1reg<=d7) am_dbase[dreg]=q1reg; else am_dbase[dreg]=zreg;
+ if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)) clear_am(p->q1.reg);
+ if(DEBUG&32) printf("is usable\n");
+ continue;
+ }
+ if((c==ADD||c==SUB)&&isconst(q2)&&zreg>=1&&zreg<=8&&isreg(z)){
+ /* add ax,#const,ax->az Test auf d8/16 fehlt noch (nicht mehr) */
+ long l;
+ if(zreg<1||zreg>8) ierror(0);
+ eval_const(&p->q2.val,p->typf);
+ l=zm2l(vmax);
+ if(c==SUB) l=-l;
+ mod_reg(zreg);
+ if(q1reg==zreg&&isreg(q1)&&am_use[zreg]&&(l==1||l==2||l==4)){
+ if(l==mopsize(am_use[zreg],zreg)&&(am_use[zreg]->code!=CONVERT||zmleq(sizetab[am_use[zreg]->typf2&NQ],sizetab[am_use[zreg]->typf&NQ]))){
+ IC *op=am_use[zreg];
+ obj *o=0;
+ if(DEBUG&32){ printf("found postincrement:\n");pric2(stdout,op);pric2(stdout,p);}
+ if((op->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&op->q1.reg==zreg){
+ if(DEBUG&32) printf("q1\n");
+ o=&op->q1;
+ }
+ if((op->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&op->q2.reg==zreg){
+ if(DEBUG&32) printf("q2\n");
+ if(o) continue; else o=&op->q2;
+ }
+ if((op->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&op->z.reg==zreg){
+ if(DEBUG&32) printf("z\n");
+ if(o) continue; else o=&op->z;
+ }
+ o->am=mymalloc(AMS);
+ o->am->basereg=zreg;
+ o->am->skal=-1;
+ o->am->dist=0;
+ o->am->dreg=0;
+ p=p->prev;
+ remove_IC(p->next);
+ clear_am(zreg);continue;
+ }
+ }
+ clear_am(q1reg);
+ if(am_dist[zreg]||am_inc[zreg]||am_use[zreg]) {clear_am(zreg);continue;} /* nur ein Offset */
+ if(isreg(q1)&&q1reg==zreg&&(l==1||l==2||l==4)){
+ /* ax+=const, fuer (ax)+ */
+ int i,f;
+ for(f=0,i=1;i<=8;i++){
+ if(am_base[i]==zreg&&!am_dreg[i]&&!am_dist[i]){
+ if(f) ierror(0);
+ am_inc[i]=l;am_dist_ic[i]=p;f=i;
+ if(DEBUG&32) printf("inc %s found\n",mregnames[i]);
+ }
+ }
+ if(f) continue;
+ }
+ am_dist[zreg]=l;
+ if(DEBUG&32) printf("dist=%ld\n",am_dist[zreg]);
+ if(CPU<68020){
+ /* bei <68020 darf der Offset nur 16bit oder 8bit bei dreg sein */
+ if((am_dreg[zreg]&&(am_dist[zreg]<-128||am_dist[zreg]>127))||am_dist[zreg]<-32768||am_dist[zreg]>32767)
+ {clear_am(zreg);continue;}
+ }
+ am_dist_ic[zreg]=p;
+ if(am_base[zreg]){
+ if(q1reg!=zreg||!isreg(q1)) {clear_am(zreg);continue;}
+ }else{
+ if(q1reg>=1&&q1reg<=8&&isreg(q1)) am_base[zreg]=q1reg; else am_base[zreg]=zreg;
+ if(DEBUG&32) printf("%s potential base for %s\n",mregnames[am_base[zreg]],mregnames[zreg]);
+ }
+ if(DEBUG&32) printf("add #const,%s found\n",mregnames[zreg]);
+ continue;
+ }
+ if(c==ADD&&q2reg>=d0&&q2reg<=d7&&isreg(q2)&&zreg>=1&&zreg<=8&&isreg(z)&&(p->q1.flags&(REG|DREFOBJ))!=(REG|DREFOBJ)){
+ /* add ax,dy->az */
+ int i;
+ if(zreg<1||zreg>8) ierror(0);
+ for(i=1;i<=8;i++)
+ if(am_dreg[i]==q2reg){ clear_am(q2reg);clear_am(i);}
+ clear_am(q1reg);
+ mod_reg(zreg);
+ if(am_dreg[zreg]||am_inc[zreg]||am_use[zreg]) {clear_am(zreg);continue;} /* nur ein Regoffset */
+ if(CPU<68020&&(am_dist[zreg]<-128||am_dist[zreg]>127))
+ {clear_am(zreg);continue;} /* bei <68020 nur 8bit Offset */
+ am_dreg[zreg]=q2reg;
+ if(ISHWORD(p->typf)) am_dreg[zreg]|=128; /* dx.w statt dx.l */
+ am_dreg_ic[zreg]=p;
+ if(am_base[zreg]){
+ if(q1reg!=zreg||!isreg(q1)) {clear_am(zreg);continue;}
+ }else{
+ if(q1reg>=1&&q1reg<=8&&isreg(q1)) am_base[zreg]=q1reg; else am_base[zreg]=zreg;
+ }
+ if(DEBUG&32) printf("add %s,%s found\n",mregnames[q2reg],mregnames[zreg]);
+ continue;
+ }
+ if(c==FREEREG){
+ /* wir koennen den Modus tatsaechlich benutzen */
+ AddressingMode *am;IC *p1,*p2;int dreg,i;
+ if(DEBUG&32) printf("freereg %s found\n",mregnames[p->q1.reg]);
+ if(q1reg>=d0&&q1reg<=d7) {am_freedreg[q1reg-8]=p;if(DEBUG&32) printf("freedreg[%d]=%lx\n",q1reg-8,(long)p);}
+ if(q1reg>8) continue;
+ if(DEBUG&32) printf("use=%p,base=%p,dist=%p,dreg=%p\n",(void*)am_use[q1reg],(void*)am_base[q1reg],(void*)am_dist[q1reg],(void*)am_dreg[q1reg]);
+ for(i=1;i<=8;i++) if(am_base[i]==q1reg) clear_am(i);
+ if(!am_use[q1reg]||!am_base[q1reg]) continue;
+ if(am_inc[q1reg]&&am_inc[q1reg]!=mopsize(am_use[q1reg],q1reg))
+ {clear_am(q1reg);continue;}
+ if(!am_dist[q1reg]&&!am_dreg[q1reg]&&!am_inc[q1reg]) continue;
+ p1=am_dist_ic[q1reg];p2=am_dreg_ic[q1reg];
+ if(DEBUG&32){
+ printf("could really use %s\n",mregnames[q1reg]);
+ if(p1) pric2(stdout,p1);
+ if(p2) pric2(stdout,p2);
+ }
+ if(am_base[q1reg]==q1reg){
+ if(p1) {p1->q2.flags=0;p1->code=ASSIGN;p1->q2.val.vmax=l2zm(4L);p1->typf=POINTER;}
+ if(p2) {p2->q2.flags=0;p2->code=ASSIGN;p2->q2.val.vmax=l2zm(4L);p2->typf=POINTER;}
+ }else{
+ if(p1) remove_IC(p1);
+ if(p2) remove_IC(p2);
+ }
+ dreg=(am_dreg[q1reg]&127)-8;
+ am=mymalloc(AMS);
+ am->skal=0;
+ am->basereg=am_base[q1reg];
+ am->dist=am_dist[q1reg];
+ am->dreg=am_dreg[q1reg];
+ if(am_inc[q1reg]) am->skal=-1;
+ if(dreg>0){
+ /* bei (d,ax,dy) das freereg dy nach hinten verschieben */
+ if(dreg<1||dreg>8) ierror(0);
+ if(p1=am_freedreg[dreg]){
+ if(DEBUG&32){
+ printf("freereg %s moved from %p to %p\n",mregnames[dreg+8],(void*)p1,(void*)p);
+ pric2(stdout,p1);
+ }
+ if(p1->code!=FREEREG){ierror(0);printf("freereg[%d]=%p\n",dreg,(void*)p1);continue;}
+ if(!p1->next) {ierror(0);continue;}
+ if(!p1->prev) {ierror(0);continue;}
+ p1->prev->next=p1->next;
+ p1->next->prev=p1->prev;
+ p1->next=p->next;
+ p1->prev=p;
+ if(p->next) p->next->prev=p1;
+ p->next=p1;
+ }
+ if(am_skal[dreg]){
+ /* Skalierung bearbeiten */
+ if(p1){
+ am->skal=am_skal[dreg];
+ am->dreg=am_dbase[dreg];
+ p1=am_shiftdreg[dreg];
+ if(DEBUG&32) pric2(stdout,p1);
+ if(am_dbase[dreg]==dreg+8){
+ p1->code=ASSIGN;p1->q2.flags=0;p1->q2.val.vmax=sizetab[p1->typf&NQ];
+ }else remove_IC(p1);
+ }
+ clear_am(dreg+8);
+ }
+ }
+ /* das hier duerfte unnoetig sein, da die Adressierungsart in */
+ /* einem IC eigentlich hoechstens einmal vorkommen darf */
+ if(q1reg<0||q1reg>8) ierror(0);
+ p1=am_use[q1reg];
+ if(DEBUG&32) pric2(stdout,p1);
+ if(p1->code==PUSH&&p1->q1.reg==q1reg&&((p1->q1.flags&(DREFOBJ|REG))==(REG))){
+ p1->q1.am=mymalloc(AMS);
+ memcpy(p1->q1.am,am,AMS);
+ p->q1.val.vmax=l2zm(0L);
+ p1->code=PEA;
+ if(DEBUG&32) printf("q1 patched\n");
+ }
+ if(p1->q1.reg==q1reg&&((p1->q1.flags&(DREFOBJ|REG))==(DREFOBJ|REG))){
+ p1->q1.am=mymalloc(AMS);
+ memcpy(p1->q1.am,am,AMS);
+ p1->q1.val.vmax=l2zm(0L);
+ if(DEBUG&32) printf("q1 patched\n");
+ }
+ if(p1->q2.reg==q1reg&&((p1->q2.flags&(DREFOBJ|REG))==(DREFOBJ|REG))){
+ p1->q2.am=mymalloc(AMS);
+ memcpy(p1->q2.am,am,AMS);
+ p1->q2.val.vmax=l2zm(0L);
+ if(DEBUG&32) printf("q2 patched\n");
+ }
+ if(p1->z.reg==q1reg&&((p1->z.flags&(DREFOBJ|REG))==(DREFOBJ|REG))){
+ p1->z.am=mymalloc(AMS);
+ memcpy(p1->z.am,am,AMS);
+ p1->z.val.vmax=l2zm(0L);
+ if(DEBUG&32) printf("z patched\n");
+ }
+ free(am);count++;
+ clear_am(q1reg);
+ continue;
+ }
+ if(c>=LABEL&&c<=BRA){
+ int i; /* ueber basic blocks hinweg unsicher */
+ for(i=1;i<=16;i++) clear_am(i);
+ continue;
+ }
+ /* Wenn Libraryaufrufe noetig sind (floating point ohne FPU oder */
+ /* 32bit mul/div/mod ohne 020+) keine Addressierungsarten nutzen */
+ if(FPU<=68000&&(ISFLOAT(p->typf)||(p->code==CONVERT&&ISFLOAT(p->typf2)))){
+ int i;
+ for(i=1;i<=16;i++) clear_am(i);
+ continue;
+ }
+ if(CPU<68020&&(c==DIV||c==MOD)){
+ int i;
+ for(i=1;i<=16;i++) clear_am(i);
+ continue;
+ }
+ if(c==PUSH&&((p->q1.flags&(DREFOBJ|REG))==REG&&q1reg<=8&&!am_use[q1reg]&&(am_inc[q1reg]||am_dist[q1reg]||am_dreg[q1reg]))){
+ if(q1reg<1||q1reg>8) ierror(0);
+ if(am_inc[q1reg]&&am_inc[q1reg]!=msizetab[p->typf&NQ]) clear_am(q1reg); else am_use[q1reg]=p;
+ if(DEBUG&32) printf("use of %s found\n",mregnames[q1reg]);
+ continue;
+ }
+ if(((p->q1.flags&(DREFOBJ|REG))==(DREFOBJ|REG)&&q1reg<=8)){
+ if(q1reg<1||q1reg>8) ierror(0);
+ if(am_use[q1reg]&&(am_use[q1reg]!=p||am_inc[q1reg])) clear_am(q1reg); else am_use[q1reg]=p;
+ if(am_inc[q1reg]&&am_inc[q1reg]!=sizetab[p->typf&NQ]) clear_am(q1reg);
+ if(DEBUG&32) printf("use of %s found\n",mregnames[q1reg]);
+ }
+ if(((p->q2.flags&(DREFOBJ|REG))==(DREFOBJ|REG)&&q2reg<=8)){
+ if(q2reg<1||q2reg>8) ierror(0);
+ if(am_use[q2reg]&&(am_use[q2reg]!=p||am_inc[q2reg])) clear_am(q2reg); else am_use[q2reg]=p;
+ if(am_inc[q2reg]&&am_inc[q2reg]!=sizetab[p->typf&NQ]) clear_am(q2reg);
+ if(DEBUG&32) printf("use of %s found\n",mregnames[q2reg]);
+ }
+ if(((p->z.flags&(DREFOBJ|REG))==(DREFOBJ|REG)&&zreg<=8)){
+ if(zreg<1||zreg>8) ierror(0);
+ if(am_use[zreg]&&(am_use[zreg]!=p||am_inc[zreg])) clear_am(zreg); else am_use[zreg]=p;
+ if(am_inc[zreg]&&am_inc[zreg]!=sizetab[p->typf&NQ]) clear_am(zreg);
+ if(DEBUG&32) printf("use of %s found\n",mregnames[zreg]);
+ }
+ if(c==ALLOCREG){
+ /* allocreg zaehlt als zerstoerung von reg */
+ p->z.flags=REG;
+ p->z.reg=zreg=q1reg=p->q1.reg;
+ }
+ if(q1reg>=1&&q1reg<=d7&&isreg(q1)&&(q1reg>8||am_use[q1reg]!=p)) clear_am(q1reg);
+ if(q2reg>=1&&q2reg<=d7&&isreg(q2)&&(q2reg>8||am_use[q2reg]!=p)) clear_am(q2reg);
+ if(zreg>=1&&zreg<=d7&&isreg(z)) clear_am(zreg);
+ if(isreg(z)&&zreg<=d7){
+ /* schauen, ob eines der Register ueberschrieben wird */
+ /* wohl noch sehr langsam */
+ mod_reg(zreg);
+ }
+ if(c==ALLOCREG) p->z.flags=0;
+ }
+ if(DEBUG&1) printf("%d addressingmodes used, localused=%d\n",count,localused);
+ return localused;
+}
+static int alignment(obj *o)
+/* versucht rauszufinden, wie ein Objekt alignet ist */
+{
+ /* wenn es keine Variable ist, kann man nichts aussagen */
+ long os;
+ if(o->am||!(o->flags&VAR)) return -1;
+ if((o->flags&DREFOBJ)){
+ if(!(o->v->flags&NOTTYPESAFE)||!ISPOINTER(o->v->vtyp->flags)||zmeqto(falign(o->v->vtyp->next),l2zm(1L)))
+ return -1;
+ else
+ return 0;
+ }
+ if(!o->v) ierror(0);
+ os=zm2l(o->val.vmax);
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+ if(!USEFRAMEPOINTER&&!vlas){
+ if(!zmleq(l2zm(0L),o->v->offset)) os=os+loff-zm2l(o->v->offset);
+ else os=os+zm2l(o->v->offset);
+ }else{
+ if(!zmleq(l2zm(0L),o->v->offset)) os=os-zm2l(o->v->offset);
+ else os=os-(zm2l(o->v->offset)+zm2l(szof(o->v->vtyp)));
+ }
+ }else{
+ if(!(o->v->flags&(TENTATIVE|DEFINED))&&zmeqto(falign(o->v->vtyp),l2zm(1L)))
+ return -1;
+ }
+
+ return os&3;
+}
+static void stored0d1(FILE *f,obj *o,int t)
+{
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(!reg_pair(o->reg,&rp)) ierror(0);
+ if(o->reg==25) return;
+ emit(f,"\tmove.l\t%s,%s\n",mregnames[d0],mregnames[rp.r1]);
+ emit(f,"\tmove.l\t%s,%s\n",mregnames[10],mregnames[rp.r2]);
+ }else{
+ if(cf&&(o->flags&(REG|DREFOBJ))!=(REG|DREFOBJ)){
+ emit(f,"\tmove.l\t%s,",mregnames[d0]);
+ emit_obj(f,o,t);
+ emit(f,"\n");
+ emit(f,"\tmove.l\t%s,",mregnames[d1]);
+ o->val.vmax=zmadd(o->val.vmax,l2zm(4L));
+ emit_obj(f,o,t);
+ o->val.vmax=zmsub(o->val.vmax,l2zm(4L));
+ emit(f,"\n");
+ }else{
+ emit(f,"\tmovem.l\t%s,",mregnames[d0d1]);
+ emit_obj(f,o,t);
+ emit(f,"\n");
+ }
+ }
+}
+static void loadd0d1(FILE *f,obj *o,int t)
+{
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(!reg_pair(o->reg,&rp))
+ ierror(0);
+ if(o->reg==25) return;
+ emit(f,"\tmove.l\t%s,%s\n",mregnames[rp.r1],mregnames[d0]);
+ emit(f,"\tmove.l\t%s,%s\n",mregnames[rp.r2],mregnames[10]);
+ }else{
+ if(cf){
+ emit(f,"\tmove.l\t");
+ emit_obj(f,o,t);
+ emit(f,",%s\n",mregnames[d0]);
+ emit(f,"\tmove.l\t");
+ o->val.vmax=zmadd(o->val.vmax,l2zm(4L));
+ emit_obj(f,o,t);
+ o->val.vmax=zmsub(o->val.vmax,l2zm(4L));
+ emit(f,",%s\n",mregnames[d1]);
+ }else{
+ emit(f,"\tmovem.l\t");
+ emit_obj(f,o,t);
+ emit(f,",%s\n",mregnames[d0d1]);
+ }
+ }
+}
+static void assign(FILE *f,IC *p,obj *q,obj *z,int c,long size,int t)
+/* Generiert Code fuer Zuweisungen und PUSH. */
+{
+ /* auch noch sehr fpu-spezifisch */
+ if(FPU<=68000&&((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)&&!((q->flags&(KONST|DREFOBJ))==KONST))
+ t=LLONG;
+ if(ISFLOAT(t)){
+ if(q&&(q->flags&(KONST|DREFOBJ))==KONST){
+ if(z&&(z->flags&(DREFOBJ|REG))==REG&&z->reg>=fp0&&z->reg<=fp7){
+ /* FP-Konstante->Register (muss immer reinpassen) */
+ if(z->reg>=fp0) emit(f,"\tfmove"); else emit(f,"\tmove");
+ emit(f,".%c\t",x_t[t&NQ]);emit_obj(f,q,t);
+ emit(f,",%s\n",mregnames[z->reg]);
+ }else{
+ /* FP-Konstante->Speicher (evtl. auf zweimal) */
+ int m,r;unsigned char *ip=(unsigned char *)&q->val.vfloat; /* nicht sehr schoen */
+ char *s;
+ if(cf&&c==ASSIGN) r=get_reg(f,1,p,0);
+ if(GAS) s="0x"; else s="$";
+ if(c==PUSH&&(t&NQ)!=FLOAT){
+ emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,-(%s)\n",s,ip[4],ip[5],ip[6],ip[7],mregnames[sp]);
+ push(4);
+ }
+ emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,",s,ip[0],ip[1],ip[2],ip[3]);
+ if(c==ASSIGN){
+ if(cf)
+ emit(f,"%s\n\tmove.l\t%s,",mregnames[r],mregnames[r]);
+ if(isreg(z)&®_pair(p->z.reg,&rp))
+ emit(f,"%s",mregnames[rp.r1]);
+ else
+ emit_obj(f,z,t);
+ }else{
+ emit(f,"-(%s)",mregnames[sp]);
+ push(4);
+ }
+ emit(f,"\n");
+ if((t&NQ)==FLOAT||c==PUSH) return;
+ m=0;
+ if(z&&(z->flags®)){
+ m=1;z->flags|=D16OFF;
+ z->val.vmax=l2zm(0L);
+ }
+ vmax=l2zm(4L);
+ z->val.vmax=zmadd(z->val.vmax,vmax);
+ emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,",s,ip[4],ip[5],ip[6],ip[7]);
+ if(cf)
+ emit(f,"%s\n\tmove.l\t%s,",mregnames[r],mregnames[r]);
+ if(isreg(z)&®_pair(p->z.reg,&rp))
+ emit(f,"%s",mregnames[rp.r2]);
+ else
+ emit_obj(f,z,t);
+ emit(f,"\n");
+ if(m){
+ z->flags&=~D16OFF;vmax=l2zm(4L);
+ z->val.vmax=zmsub(z->val.vmax,vmax);
+ }
+ }
+ return;
+ }
+ if((q&&(q->flags®)&&q->reg>=fp0)||(z&&(z->flags®)&&z->reg>=fp0)){
+ if(c==ASSIGN&&(q->flags®)&&(z->flags®)&&q->reg==z->reg) return;
+ if(c==ASSIGN){ move(f,q,0,z,0,t);return;}
+ emit(f,"\tfmove.%c\t",x_t[t&NQ]);
+ emit_obj(f,q,t);
+ emit(f,",");
+ if(c==PUSH){
+ emit(f,"-(%s)",mregnames[sp]);
+ push(size);
+ } else
+ emit_obj(f,z,t);
+ emit(f,"\n");return;
+ }
+ if(size==8) t=LLONG;
+ }
+ if((t&NQ)==LLONG){
+ if(z&&compare_objects(q,z)) return;
+ if(((cf&&c==ASSIGN)||(q->flags&(REG|DREFOBJ))==REG)&&(!z||(z->flags&(REG|DREFOBJ))!=REG)){
+ if(cf){
+ if(c==ASSIGN){
+ int r;
+ if((q->flags&(REG|DREFOBJ))==REG){
+ if(!reg_pair(q->reg,&rp)) ierror(0);
+ r=rp.r2;
+ }else{
+ r=get_reg(f,1,p,0);
+ emit(f,"\tmove.l\t");
+ emit_lword(f,q);
+ emit(f,",%s\n",mregnames[r]);
+ }
+ emit(f,"\tmove.l\t%s,",mregnames[r]);
+ emit_lword(f,z);
+ emit(f,"\n");
+ if((q->flags&(REG|DREFOBJ))==REG){
+ r=rp.r1;
+ }else{
+ emit(f,"\tmove.l\t");
+ emit_hword(f,q);
+ emit(f,",%s\n",mregnames[r]);
+ }
+ emit(f,"\tmove.l\t%s,",mregnames[r]);
+ emit_hword(f,z);
+ emit(f,"\n");
+ }else{
+ emit(f,"\tsubq.l\t#8,%s\n",mregnames[sp]);
+ push(8);
+ emit(f,"\tmovem.l\t%s,(%s)\n",mregnames[q->reg],mregnames[sp]);
+ }
+ }else{
+ emit(f,"\tmovem.l\t%s,",mregnames[q->reg]);
+ if(c==ASSIGN){
+ emit_obj(f,z,t);
+ }else{
+ emit(f,"-(%s)",mregnames[sp]);
+ push(8);
+ }
+ emit(f,"\n");
+ }
+ return;
+ }
+ if(!cf&&(q->flags&(REG|DREFOBJ))!=REG&&!((q->flags&(KONST|DREFOBJ))==KONST)&&z&&(z->flags&(REG|DREFOBJ))==REG){
+ emit(f,"\tmovem.l\t");
+ emit_obj(f,q,t);
+ emit(f,",%s\n",mregnames[z->reg]);
+ return;
+ }
+ emit(f,"\tmove.l\t");
+ emit_lword(f,q);
+ emit(f,",");
+ if(c==ASSIGN){
+ emit_lword(f,z);
+ }else{
+ emit(f,"-(%s)",mregnames[sp]);
+ push(4);
+ }
+ emit(f,"\n");
+ emit(f,"\tmove.l\t");
+ emit_hword(f,q);
+ emit(f,",");
+ if(c==ASSIGN){
+ emit_hword(f,z);
+ }else{
+ emit(f,"-(%s)",mregnames[sp]);
+ push(4);
+ }
+ emit(f,"\n");
+ return;
+ }
+ if((size==1||size==2||size==4)&&!ISARRAY(t)&&(p->code!=PUSH||zm2l(p->z.val.vmax)!=3)&&((t&NQ)!=CHAR||size==1)){
+ if(ISSTRUCT(t)||ISUNION(t)){
+ if(p->code==PUSH&&!zmeqto(p->q2.val.vmax,p->z.val.vmax)){
+ if(size!=4&&size!=2) ierror(size);
+ emit(f,"\tsubq.%s\t#%d,%s\n",cf?"l":"w",size,mregnames[sp]);
+ push(size);
+ size=zm2l(p->z.val.vmax);
+ if(size!=1&&size!=2) ierror(0);
+ emit(f,"\tmove.%c\t",size==1?'b':'w');
+ emit_obj(f,q,(size==1?CHAR:SHORT));
+ emit(f,",(%s)\n",mregnames[sp]);
+ return;
+ }else{
+ if(size==1)
+ t=CHAR;
+ else if(size==2)
+ t=SHORT;
+ else
+ t=LONG;
+ }
+ }
+ if(c==ASSIGN){move(f,q,0,z,0,t);return;}
+ /* Sonderfall pea */
+ if((q->flags&VARADR)&&c==PUSH){
+ emit(f,"\tpea\t");
+ q->flags&=~VARADR; emit_obj(f,q,t); q->flags|=VARADR;
+ emit(f,"\n");
+ push(size);
+ return;
+ }
+ emit(f,"\tmove.%c\t",x_s[size]);
+ emit_obj(f,q,t);
+ emit(f,",");
+ if(c==PUSH){
+ emit(f,"-(%s)",mregnames[sp]);
+ push(size);
+ } else
+ emit_obj(f,z,t);
+ emit(f,"\n");return;
+ }else{
+ int a1,a2,qreg,zreg,dreg,loops,scratch=0,down=0;char *cpstr;
+ long s=size,osize=size;
+ IC *m;
+ for(m=p->next;m&&m->code==FREEREG;m=m->next){
+ if(q&&m->q1.reg==q->reg) scratch|=1;
+ if(z&&m->q1.reg==z->reg) scratch|=2;
+ }
+ a1=alignment(q);
+ if(c!=PUSH) a2=alignment(z); else a2=0;
+ if(a1<0||a2<0) {a1=1;a2=2;}
+ if(p->typf2==2||p->typf2==4) {a1=a2=0;}
+ if((c==PUSH||(scratch&1))&&(q->flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&q->reg>=1&&q->reg<=8&&!q->am){
+ qreg=q->reg;
+ if(c==PUSH&&(a1&1)==0&&(a2&1)==0)
+ emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[s<=8],strshort[s<=32767],(long)s,mregnames[q->reg]);
+ }else{
+ if(c!=ASSIGN&&!regavailable(0))
+ qreg=pget_reg(f,0,p,0);
+ else
+ qreg=get_reg(f,0,p,0);
+ if(c==PUSH&&(a1&1)==0&&(a2&1)==0){
+ q->flags|=D16OFF;
+ q->val.vmax=zmadd(q->val.vmax,l2zm((long)s));
+ emit(f,"\tlea\t");emit_obj(f,q,POINTER);
+ q->val.vmax=zmsub(q->val.vmax,l2zm((long)s));
+ emit(f,",%s\n",mregnames[qreg]);
+ }else{
+ emit(f,"\tlea\t");emit_obj(f,q,POINTER);
+ emit(f,",%s\n",mregnames[qreg]);
+ }
+ }
+ if(c==PUSH){
+ if((a1&1)==0&&(a2&1)==0){
+ zreg=8;
+ }else{
+ emit(f,"\tsub%s.%s\t#%ld,%s\n",quick[s<=8],strshort[s<=32767],(long)s,mregnames[sp]);
+ push(size);
+ size=0;
+ if(!regavailable(0))
+ zreg=pget_reg(f,0,p,0);
+ else
+ zreg=get_reg(f,0,p,0);
+ emit(f,"\tmove.l\t%s,%s\n",mregnames[sp],mregnames[zreg]);
+ }
+ }else{
+ if((scratch&2)&&(z->flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&z->reg>=1&&z->reg<=8&&!z->am){
+ zreg=z->reg;
+ }else{
+ zreg=get_reg(f,0,p,0);
+ emit(f,"\tlea\t");emit_obj(f,z,POINTER);
+ emit(f,",%s\n",mregnames[zreg]);
+ }
+ }
+ /* wenn Typ==CHAR, dann ist das ein inline_memcpy und wir nehmen */
+ /* das unguenstigste Alignment an */
+ /*if((t&NQ)==CHAR){ a1=1;a2=2;}*/
+
+ if(c==PUSH&&(a1&1)==0&&(a2&1)==0){
+ cpstr="\tmove.%c\t-(%s),-(%s)\n";
+ down=1;
+ }else
+ cpstr="\tmove.%c\t(%s)+,(%s)+\n";
+
+ if((a1&1)&&(a2&1)){emit(f,cpstr,'b',mregnames[qreg],mregnames[zreg]);s--;a1&=~1;a2&=~1;}
+ if((a1&2)&&(a2&2)){emit(f,cpstr,'w',mregnames[qreg],mregnames[zreg]);s-=2;a1&=~2;a2&=~2;}
+ if(!(a1&1)&&!(a2&1)) loops=s/16-1; else loops=s/4-1;
+ if(loops>0){
+ if(c!=ASSIGN&&!regavailable(1)) dreg=pget_reg(f,1,p,0);
+ else dreg=get_reg(f,1,p,0);
+ emit(f,"\tmove%s.l\t#%d,%s\n%s%d:\n",quick[loops>=-128&&loops<=127],loops,mregnames[dreg],labprefix,++label);
+ }
+ if(loops>=0){
+ int t;
+ if(!(a1&1)&&!(a2&1)) t='l'; else t='b';
+ emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]);
+ emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]);
+ emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]);
+ emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]);
+ }
+ if(loops>0){
+ if(!cf&&loops<=32767&&loops>=-32768){
+ emit(f,"\tdbra\t%s,%s%d\n",mregnames[dreg],labprefix,label);
+ }else{
+ emit(f,"\tsubq.l\t#1,%s\n\tbge\t%s%d\n",mregnames[dreg],labprefix,label);
+ }
+ }
+ if(!(a1&1)&&!(a2&1)){
+ if(s&8){
+ emit(f,cpstr,'l',mregnames[qreg],mregnames[zreg]);
+ emit(f,cpstr,'l',mregnames[qreg],mregnames[zreg]);
+ }
+ if(s&4) emit(f,cpstr,'l',mregnames[qreg],mregnames[zreg]);
+ if(s&2) emit(f,cpstr,'w',mregnames[qreg],mregnames[zreg]);
+ if(s&1) emit(f,cpstr,'b',mregnames[qreg],mregnames[zreg]);
+ }else{
+ s&=3;
+ while(s){emit(f,cpstr,'b',mregnames[qreg],mregnames[zreg]);s--;}
+ }
+ if(c==PUSH&&qreg==q->reg&&(!(scratch&1))&&!down)
+ emit(f,"\tsub%s.%s\t#%ld,%s\n",quick[osize<=8],strshort[osize<=32767],osize,regnames[qreg]);
+ if(c==PUSH) push(size);
+ }
+ return;
+}
+static int muststore(IC *p,int r)
+{
+ if(!regs[r])
+ return 0;
+#if 0
+ /* mal bei Gelegenheit testen */
+ while(p){
+ if(p->code==FREEREG&&p->q1.reg==r)
+ return 0;
+ if((p->q1.flags®)&&p->q1.reg==r)
+ return 1;
+ if(p->q1.am&&(p->q1.am->basereg==r||(p->q1.am->dreg&127)==r))
+ return 1;
+ if((p->q2.flags®)&&p->q2.reg==r)
+ return 1;
+ if(p->q2.am&&(p->q2.am->basereg==r||(p->q2.am->dreg&127)==r))
+ return 1;
+ if(p->z.am&&(p->z.am->basereg==r||(p->z.am->dreg&127)==r))
+ return 1;
+ if((p->z.flags®)&&p->z.reg==r)
+ return (p->z.flags&DREFOBJ)!=0;
+ if(p->code>=LABEL&&p->code<=BRA)
+ return 1;
+ p=p->next;
+ }
+ return 0;
+#else
+ return 1;
+#endif
+}
+
+static int store_saveregs;
+static void saveregswfp(FILE *f,IC *p,int storefp)
+{
+ int dontsave;
+ store_saveregs=0;
+ if((p->z.flags&(REG|DREFOBJ))==REG) dontsave=p->z.reg; else dontsave=0;
+ if(dontsave!= d0&&dontsave!=25&&(muststore(p,d0)||muststore(p,d0d1))) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[d0],mregnames[sp]);push(4);store_saveregs|=1;}
+ if(dontsave!=10&&dontsave!=25&&(muststore(p,d1)||muststore(p,d0d1))) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[d1],mregnames[sp]);push(4);store_saveregs|=2;}
+ if(dontsave!= fp0&&muststore(p,fp0)) {emit(f,"\tfmove.x\t%s,-(%s)\n",mregnames[fp0],mregnames[sp]);push(12);store_saveregs|=16;}
+ if(dontsave!= fp1&&muststore(p,fp1)) {emit(f,"\tfmove.x\t%s,-(%s)\n",mregnames[fp1],mregnames[sp]);push(12);store_saveregs|=32;}
+ if(dontsave!= a0&&muststore(p,a0)) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[a0],mregnames[sp]);push(4);store_saveregs|=4;}
+ if(dontsave!= a1&&muststore(p,a1)) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[a1],mregnames[sp]);push(4);store_saveregs|=8;}
+
+}
+static void restoreregsa(FILE *f,IC *p)
+{
+ if(store_saveregs&8) {emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[a1]);pop(4);}
+ if(store_saveregs&4) {emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[a0]);pop(4);}
+}
+static void restoreregsd(FILE *f,IC *p)
+{
+ int dontsave;
+ if((p->z.flags&(REG|DREFOBJ))==REG) dontsave=p->z.reg; else dontsave=0;
+ if(dontsave!=fp1&&(store_saveregs&32)){
+ emit(f,"\tfmove.x\t(%s)+,%s\n",mregnames[sp],mregnames[fp1]);
+ pop(12);
+ }
+ if(dontsave!=fp0&&(store_saveregs&16)){
+ emit(f,"\tfmove.x\t(%s)+,%s\n",mregnames[sp],mregnames[fp0]);
+ pop(12);
+ }
+ if(dontsave!=10&&(store_saveregs&2)){
+ if(!GAS&&!PHXASS)
+ emit(f,"\topt\tom-\n");
+ if(cf)
+ emit(f,"\tmovem.l\t(%s),%s\n\taddq.l\t#4,%s\n",mregnames[sp],mregnames[d1],mregnames[sp]);
+ else
+ emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],mregnames[d1]);
+ pop(4);
+ if(!GAS&&!PHXASS)
+ emit(f,"\topt\tom+\n");
+ }
+ if(dontsave!=d0 &&(store_saveregs&1)){
+ if(!GAS&&!PHXASS)
+ emit(f,"\topt\tom-\n");
+ if(cf)
+ emit(f,"\tmovem.l\t(%s),%s\n\taddq.l\t#4,%s\n",mregnames[sp],mregnames[d0],mregnames[sp]);
+ else
+ emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],mregnames[d0]);
+ pop(4);
+ if(!GAS&&!PHXASS)
+ emit(f,"\topt\tom+\n");
+ }
+}
+
+/* emits the low word of a long long object */
+static void emit_lword(FILE *f,obj *o)
+{
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(!reg_pair(o->reg,&rp))
+ ierror(0);
+ emit(f,"%s",mregnames[rp.r2]);
+ }else if((o->flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&o->val,UNSIGNED|LLONG);
+ vumax=zumand(vumax,ul2zum(0xffffffff));
+ insert_const(&gval,UNSIGNED|MAXINT);
+ emit(f,"#");
+ emitval(f,&gval,UNSIGNED|MAXINT);
+ }else{
+ if(o->am||(o->flags®)){
+ o->flags|=D16OFF;
+ o->val.vmax=l2zm(0L);
+ }
+ o->val.vmax=zmadd(o->val.vmax,l2zm(4L));
+ emit_obj(f,o,LLONG);
+ o->flags&=~D16OFF;
+ o->val.vmax=zmsub(o->val.vmax,l2zm(4L));
+ }
+}
+/* emits the high word of a long long object */
+static void emit_hword(FILE *f,obj *o)
+{
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(!reg_pair(o->reg,&rp))
+ ierror(0);
+ emit(f,"%s",mregnames[rp.r1]);
+ }else if((o->flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&o->val,UNSIGNED|MAXINT);
+ vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff));
+ insert_const(&gval,UNSIGNED|MAXINT);
+ emit(f,"#");
+ emitval(f,&gval,UNSIGNED|MAXINT);
+ }else{
+ emit_obj(f,o,LONG);
+ }
+}
+/* process ICs with long long; return 1 if IC has been handled */
+static int handle_llong(FILE *f,IC *p)
+{
+ int c=p->code,r=0,t=p->typf&NU;
+ char *libfuncname;
+
+ if(c==ADDRESS) return 0;
+
+ cc_set=0;
+ if(c==GETRETURN){
+ if(isreg(z)&&p->z.reg==25)
+ return 1;
+ emit(f,"\tmove.l\t%s,",mregnames[d1]);
+ emit_lword(f,&p->z);
+ emit(f,"\n");
+ emit(f,"\tmove.l\t%s,",mregnames[d0]);
+ emit_hword(f,&p->z);
+ emit(f,"\n");
+ return 1;
+ }
+ if(c==SETRETURN){
+ if(isreg(q1)&&p->q1.reg==25)
+ return 1;
+ emit(f,"\tmove.l\t");
+ emit_lword(f,&p->q1);
+ emit(f,",%s\n",mregnames[d1]);
+ emit(f,"\tmove.l\t");
+ emit_hword(f,&p->q1);
+ emit(f,",%s\n",mregnames[d0]);
+ return 1;
+ }
+ if(c==CONVERT){
+ int told=q1typ(p),tnew=ztyp(p);
+ if(ISPOINTER(told)) told=UNSIGNED|LONG;
+ if(ISPOINTER(tnew)) tnew=UNSIGNED|LONG;
+ if(ISFLOAT(told)){
+ if(!OLD_SOFTFLOAT) ierror(0);
+ saveregs(f,p);
+ assign(f,p,&p->q1,0,PUSH,msizetab[told&NQ],told);
+ scratch_modified();
+ if(GAS)
+ emit(f,"\t.global\t__flt%ldto%cint64\n\tjbsr\t__flt%ldto%cint64\n\taddq.%s\t#%ld,%s\n",msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',strshort[1],msizetab[told&NQ],mregnames[sp]);
+ else
+ emit(f,"\tpublic\t__flt%ldto%cint64\n\tjsr\t__flt%ldto%cint64\n\taddq.%s\t#%ld,%s\n",msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',strshort[1],msizetab[told&NQ],mregnames[sp]);
+ pop(msizetab[told]);
+ restoreregsa(f,p);
+ if(!isreg(z)||p->z.reg!=25){ /* d0/d1 */
+ emit(f,"\tmove.l\t%s,",mregnames[d1]);
+ emit_lword(f,&p->z);
+ emit(f,"\n");
+ emit(f,"\tmove.l\t%s,",mregnames[d0]);
+ emit_hword(f,&p->z);
+ emit(f,"\n");
+ }
+ restoreregsd(f,p);
+ return 1;
+ }
+ if(ISFLOAT(tnew)){
+ saveregswfp(f,p,1);
+ assign(f,p,&p->q1,0,PUSH,msizetab[told&NQ],told);
+ scratch_modified();
+ if(GAS)
+ emit(f,"\t.global\t__%cint64toflt%ld\n\tjbsr\t__%cint64toflt%ld\n\taddq.%s\t#%ld,%s\n",(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,strshort[1],msizetab[told&NQ],mregnames[sp]);
+ else
+ emit(f,"\tpublic\t__%cint64toflt%ld\n\tjsr\t__%cint64toflt%ld\n\taddq.%s\t#%ld,%s\n",(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,strshort[1],msizetab[told&NQ],mregnames[sp]);
+ pop(msizetab[told&NQ]);
+ restoreregsa(f,p);
+ if(FPU>68000){
+ emit(f,"\tfmove.x\tfp0,");
+ emit_obj(f,&p->z,tnew);
+ emit(f,"\n");
+ }else if((tnew&NQ)==FLOAT){
+ emit(f,"\tmove.l\t%s,",mregnames[d0]);
+ emit_obj(f,&p->z,tnew);
+ emit(f,"\n");
+ }else{
+ emit(f,"\tmove.l\td1,");
+ emit_lword(f,&p->z);
+ emit(f,"\n");
+ emit(f,"\tmove.l\t%s,",mregnames[d0]);
+ emit_hword(f,&p->z);
+ emit(f,"\n");
+ }
+ restoreregsd(f,p);
+ return 1;
+ }
+ if((told&NQ)<LLONG){
+ int destreg=0;
+ if(ISHWORD(told)||!(told&UNSIGNED)){
+ if(isreg(z)){
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ r=rp.r2;
+ destreg=1;
+ }else{
+ r=get_reg(f,1,p,0);
+ }
+ loadext(f,r,&p->q1,told);
+ p->q1.flags=REG;
+ p->q1.reg=r;
+ p->q1.am=0;
+ }
+ if(!destreg){
+ emit(f,"\tmove.l\t");
+ emit_obj(f,&p->q1,told);
+ emit(f,",");
+ emit_lword(f,&p->z);
+ emit(f,"\n");
+ }
+ if(told&UNSIGNED){
+ emit(f,"\tmove.l\t#0,");
+ emit_hword(f,&p->z);
+ emit(f,"\n");
+ }else{
+ int tmp;
+ if(r==0)
+ ierror(0);
+ if(destreg){
+ emit(f,"\tmove.l\t%s,%s\n",mregnames[r],mregnames[rp.r1]);
+ r=rp.r1;
+ }
+ tmp=get_reg(f,1,p,0);
+ emit(f,"\tmoveq\t#31,%s\n",mregnames[tmp]);
+ emit(f,"\tasr.l\t%s,%s\n",mregnames[tmp],mregnames[r]);
+ if(!destreg){
+ emit(f,"\tmove.l\t%s,",mregnames[r]);
+ emit_hword(f,&p->z);
+ emit(f,"\n");
+ }
+ }
+ return 1;
+ }
+ if((tnew&NQ)<LLONG){
+ if((tnew&NQ)<INT&&!isreg(z)){
+ r=get_reg(f,1,p,0);
+ emit(f,"\tmove.l\t");
+ emit_lword(f,&p->q1);
+ emit(f,",%s\n",mregnames[r]);
+ emit(f,"\tmove.%c\t%s,",x_t[tnew&NQ],mregnames[r]);
+ emit_obj(f,&p->z,tnew);
+ emit(f,"\n");
+ }else{
+ emit(f,"\tmove.%c\t",x_t[tnew&NQ]);
+ p->q1.val.vmax=zmadd(p->q1.val.vmax,zmsub(sizetab[LONG],sizetab[tnew&NQ]));
+ emit_lword(f,&p->q1);
+ emit(f,",");
+ emit_obj(f,&p->z,tnew);
+ emit(f,"\n");
+ }
+ return 1;
+ }
+ assign(f,p,&p->q1,&p->z,ASSIGN,msizetab[t],t);
+ return 1;
+ }
+ if(c==ASSIGN){
+ assign(f,p,&p->q1,&p->z,ASSIGN,msizetab[t],t);
+ return 1;
+ }
+ if(c==PUSH){
+ dontpop+=zm2l(p->q2.val.vmax);
+ assign(f,p,&p->q1,0,PUSH,msizetab[t],t);
+ return 1;
+ }
+ if(c==MINUS||c==KOMPLEMENT){
+ char *sl,*sh;
+ if(c==MINUS){
+ sl="neg.l";
+ sh="negx.l";
+ }else
+ sl=sh="not.l";
+ if(!cf&&compare_objects(&p->q1,&p->z)){
+ emit(f,"\t%s\t",sl);
+ emit_lword(f,&p->z);
+ emit(f,"\n");
+ emit(f,"\t%s\t",sh);
+ emit_hword(f,&p->z);
+ emit(f,"\n");
+ return 1;
+ }
+ if(isreg(z)){
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ assign(f,p,&p->q1,&p->z,ASSIGN,msizetab[t],t);
+ emit(f,"\t%s\t%s\n",sl,mregnames[rp.r2]);
+ emit(f,"\t%s\t%s\n",sh,mregnames[rp.r1]);
+ return 1;
+ }
+ r=get_reg(f,1,p,0);
+ emit(f,"\tmove.l\t");
+ emit_lword(f,&p->q1);
+ emit(f,",%s\n",mregnames[r]);
+ emit(f,"\t%s\t%s\n",sl,mregnames[r]);
+ emit(f,"\tmove.l\t%s,",mregnames[r]);
+ emit_lword(f,&p->z);
+ emit(f,"\n");
+ emit(f,"\tmove.l\t");
+ emit_hword(f,&p->q1);
+ emit(f,",%s\n",mregnames[r]);
+ emit(f,"\t%s\t%s\n",sh,mregnames[r]);
+ emit(f,"\tmove.l\t%s,",mregnames[r]);
+ emit_hword(f,&p->z);
+ emit(f,"\n");
+ return 1;
+ }
+ if((c>=OR&&c<=AND)||c==ADD||c==SUB){
+ char *sl,*sh;int t2=0;
+ switch_IC(p);
+ if(c==ADD){sl="add.l";sh="addx.l";}
+ else if(c==SUB){sl="sub.l";sh="subx.l";}
+ else if(c==AND){sl=sh="and.l";}
+ else if(c==OR){sl=sh="or.l";}
+ else if(c==XOR){sl=sh="eor.l";}
+ else
+ ierror(0);
+ if(isreg(q1)&&isreg(q2)&&isreg(z)&&p->q1.reg==p->q2.reg&&p->q1.reg==p->z.reg){
+ if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+ emit(f,"\t%s\t%s,%s\n",sl,mregnames[rp.r2],mregnames[rp.r2]);
+ emit(f,"\t%s\t%s,%s\n",sh,mregnames[rp.r1],mregnames[rp.r1]);
+ return 1;
+ }
+ if(!isreg(z)&&compare_objects(&p->q1,&p->z)){
+ if(isreg(q2)||(isconst(q2)&&(c==ADD||c==SUB)&&!cf)){
+ if(!r) r=get_reg(f,1,p,0);
+ emit(f,"\t%s\t",sl);
+ emit_lword(f,&p->q2);
+ }else{
+ if(!r) r=get_reg(f,1,p,0);
+ emit(f,"\tmove.l\t");
+ emit_lword(f,&p->q2);
+ emit(f,",%s\n",mregnames[r]);
+ emit(f,"\t%s\t%s",sl,mregnames[r]);
+ }
+ emit(f,",");
+ emit_lword(f,&p->z);
+ emit(f,"\n");
+ if(!isreg(q2)||c==ADD||c==SUB||c==XOR){
+ emit(f,"\tmove.l\t");
+ emit_hword(f,&p->q1);
+ emit(f,",%s\n",mregnames[r]);
+ if(isreg(q2)){
+ if(!reg_pair(p->q2.reg,&rp)) ierror(0);
+ t2=rp.r1;
+ }else{
+ t2=get_reg(f,1,p,0);
+ emit(f,"\tmove.l\t");
+ emit_hword(f,&p->q2);
+ emit(f,",%s\n",mregnames[t2]);
+ }
+ emit(f,"\t%s\t%s,%s\n",sh,mregnames[t2],mregnames[r]);
+ emit(f,"\tmove.l\t%s,",mregnames[r]);
+ emit_hword(f,&p->z);
+ emit(f,"\n");
+ }else{
+ if(isreg(q2)){
+ emit(f,"\t%s\t",sh);
+ emit_hword(f,&p->q2);
+ }else{
+ if(!r) r=get_reg(f,1,p,0);
+ emit(f,"\tmove.l\t");
+ emit_hword(f,&p->q2);
+ emit(f,",%s\n",mregnames[r]);
+ emit(f,"\t%s\t%s",sh,mregnames[r]);
+ }
+ emit(f,",");
+ emit_hword(f,&p->z);
+ emit(f,"\n");
+ }
+ return 1;
+ }
+ if(isreg(z)&&(!isreg(q2)||p->z.reg!=p->q2.reg)){
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ r=rp.r2;
+ }else{
+ r=get_reg(f,1,p,0);
+ }
+ if(!compare_objects(&p->q1,&p->z)){
+ emit(f,"\tmove.l\t");
+ emit_lword(f,&p->q1);
+ emit(f,",%s\n",mregnames[r]);
+ }
+ if(c==XOR){
+ t2=get_reg(f,1,p,0);
+ emit(f,"\tmove.l\t");
+ emit_lword(f,&p->q2);
+ emit(f,",%s\n",mregnames[t2]);
+ emit(f,"\t%s\t%s,%s\n",sl,mregnames[t2],mregnames[r]);
+ }else{
+ emit(f,"\t%s\t",sl);
+ emit_lword(f,&p->q2);
+ emit(f,",%s\n",mregnames[r]);
+ }
+ if(isreg(z)&&(!isreg(q2)||p->z.reg!=p->q2.reg)){
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ r=rp.r1;
+ }else{
+ emit(f,"\tmove.l\t%s,",mregnames[r]);
+ emit_lword(f,&p->z);
+ emit(f,"\n");
+ }
+ if(!compare_objects(&p->q1,&p->z)){
+ emit(f,"\tmove.l\t");
+ emit_hword(f,&p->q1);
+ emit(f,",%s\n",mregnames[r]);
+ }
+ if(c==XOR||c==ADD||c==SUB){
+ if(isreg(q2)){
+ if(!reg_pair(p->q2.reg,&rp)) ierror(0);
+ t2=rp.r1;
+ }else{
+ if(!t2) t2=get_reg(f,1,p,0);
+ emit(f,"\tmove.l\t");
+ emit_hword(f,&p->q2);
+ emit(f,",%s\n",mregnames[t2]);
+ }
+ emit(f,"\t%s\t%s,%s\n",sh,mregnames[t2],mregnames[r]);
+ }else{
+ emit(f,"\t%s\t",sh);
+ emit_hword(f,&p->q2);
+ emit(f,",%s\n",mregnames[r]);
+ }
+ if(!isreg(z)||(isreg(q2)&&p->z.reg==p->q2.reg)){
+ emit(f,"\tmove.l\t%s,",mregnames[r]);
+ emit_hword(f,&p->z);
+ emit(f,"\n");
+ }
+ return 1;
+ }
+ if(c==TEST){
+ p->code=c=COMPARE;
+ p->q2.flags=KONST;
+ if((t&NU)==LLONG)
+ p->q2.val.vllong=zm2zll(l2zm(0L));
+ else if((t&NU)==(UNSIGNED|LLONG))
+ p->q2.val.vullong=zum2zull(ul2zum(0UL));
+ else
+ ierror(0);
+ }
+ if(c==COMPARE){
+ int rl,rh,t2;
+ comptyp=p->typf;
+ rl=get_reg(f,1,p,0);
+ rh=get_reg(f,1,p,0);
+ emit(f,"\tmove.l\t");
+ emit_lword(f,&p->q1);
+ emit(f,",%s\n",mregnames[rl]);
+ emit(f,"\tmove.l\t");
+ emit_hword(f,&p->q1);
+ emit(f,",%s\n",mregnames[rh]);
+ if(isreg(q2)){
+ if(!reg_pair(p->q2.reg,&rp)) ierror(0);
+ t2=rp.r1;
+ }else{
+ t2=get_reg(f,1,p,0);
+ emit(f,"\tmove.l\t");
+ emit_hword(f,&p->q2);
+ emit(f,",%s\n",mregnames[t2]);
+ }
+ emit(f,"\tsub.l\t");
+ emit_lword(f,&p->q2);
+ emit(f,",%s\n",mregnames[rl]);
+ emit(f,"\tsubx.l\t%s,%s\n",mregnames[t2],mregnames[rh]);
+ return 1;
+ }
+ saveregs(f,p);
+ if((c==LSHIFT||c==RSHIFT)&&(q2typ(p)&NQ)==LLONG){
+ emit(f,"\tmove.l\t");
+ emit_lword(f,&p->q2);
+ emit(f,",-(%s)\n",mregnames[sp]);
+ push(4);
+ }else
+ assign(f,p,&p->q2,0,PUSH,msizetab[q2typ(p)&NQ],q2typ(p));
+ assign(f,p,&p->q1,0,PUSH,msizetab[q1typ(p)&NQ],q1typ(p));
+ scratch_modified();
+ if(c==MULT){
+ if(CPU==68060)
+ libfuncname="__mulint64_060";
+ else if(CPU>=68020)
+ libfuncname="__mulint64_020";
+ else
+ libfuncname="__mulint64";
+ }else if(c==DIV){
+ if(t&UNSIGNED){
+ if(CPU==68060)
+ libfuncname="__divuint64_060";
+ else if(CPU>=68020)
+ libfuncname="__divuint64_020";
+ else
+ libfuncname="__divuint64";
+ }else{
+ if(CPU==68060)
+ libfuncname="__divsint64_060";
+ else if(CPU>=68020)
+ libfuncname="__divsint64_020";
+ else
+ libfuncname="__divsint64";
+ }
+ }else if(c==MOD){
+ if(t&UNSIGNED){
+ if(CPU==68060)
+ libfuncname="__moduint64_060";
+ else if(CPU>=68020)
+ libfuncname="__moduint64_020";
+ else
+ libfuncname="__moduint64";
+ }else{
+ if(CPU==68060)
+ libfuncname="__modsint64_060";
+ else if(CPU>=68020)
+ libfuncname="__modsint64_020";
+ else
+ libfuncname="__modsint64";
+ }
+ }else if(c==RSHIFT){
+ if(t&UNSIGNED)
+ libfuncname="__rshuint64";
+ else
+ libfuncname="__rshsint64";
+ }else if(c==LSHIFT)
+ libfuncname="__lshint64";
+ else{
+ printf("c=%d\n",c);
+ ierror(0);
+ }
+ if(GAS)
+ emit(f,"\t.global\t%s\n\tjbsr\t%s\n",libfuncname,libfuncname);
+ else
+ emit(f,"\tpublic\t%s\n\tjsr\t%s\n",libfuncname,libfuncname);
+ if(c==LSHIFT||c==RSHIFT){
+#ifdef M68K_16BIT_INT
+ emit(f,"\tadd.%s\t#10,%s\n",strshort[1],mregnames[sp]);
+ pop(10);
+#else
+ emit(f,"\tadd.%s\t#12,%s\n",strshort[1],mregnames[sp]);
+ pop(12);
+#endif
+ }else{
+ emit(f,"\tadd.%s\t#16,%s\n",strshort[1],mregnames[sp]);
+ pop(16);
+ }
+ restoreregsa(f,p);
+ if(!isreg(z)||p->z.reg!=25){
+ emit(f,"\tmove.l\t%s,",mregnames[d0]);
+ emit_hword(f,&p->z);
+ emit(f,"\n");
+ emit(f,"\tmove.l\t%s,",mregnames[10]);
+ emit_lword(f,&p->z);
+ emit(f,"\n");
+ }
+ restoreregsd(f,p);
+ return 1;
+}
+
+/* generate inlines for Amiga IEEE softcalls */
+static char *ami_ieee(char *base,int off)
+{
+ char *s;
+ if(cf) ierror(0);
+ s=mymalloc(128);
+ sprintf(s,"\tmove.l\t%s,-(%s)\n\tmove.l\t%sMathIeee%sBase%s,%s\n\tjsr\t%d(%s)\n\tmove.l\t(%s)+,%s",mregnames[a6],mregnames[sp],idprefix,base,use_sd?"(a4)":"",mregnames[a6],off,mregnames[a6],mregnames[sp],mregnames[a6]);
+ return s;
+}
+
+/****************************************/
+/* End of private fata and functions. */
+/****************************************/
+
+
+
+int init_cg(void)
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+{
+ int i;
+ larray.size=l2zm(3L);
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(4L);
+ char_bit=l2zm(8L);
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+ for(i= 1;i<=16;i++) {regsize[i]=l2zm( 4L);regtype[i]=<yp;}
+ for(i=fp0;i<=fp7;i++) {regsize[i]=l2zm(12L);regtype[i]=&larray;}
+ for(i=25;i<=28;i++) {regsize[i]=l2zm( 8L);regtype[i]=&lltyp;}
+
+ if(ELF){
+ for(i=1;i<=MAXR;i++)
+ mregnames[i]=elfregnames[i];
+ idprefix="";
+ labprefix=".l";
+ rprefix="%";
+ }else{
+ for(i=1;i<=MAXR;i++)
+ mregnames[i]=regnames[i];
+ idprefix="_";
+ labprefix="l";
+ rprefix="";
+ }
+
+ if(SMALLDATA) use_sd=1;
+
+
+ /* default CPU is 68000 */
+ if(!(g_flags[0]&USEDFLAG)) CPU=68000;
+ if(CPU==68040) static_cse=0; else static_cse=1;
+ if(CPU<68000) cf=1;
+ if(cf) MINADDI2P=INT; /* requires 32bit int! */
+ /* no FPU by default */
+ if(!(g_flags[1]&USEDFLAG)) FPU=0;
+ if(FPU<=68000) {x_t[FLOAT]='l';}
+ if(D2SCRATCH){regscratch[d2]=1;dscratch++;}
+ if(A2SCRATCH) {regscratch[a2]=1;ascratch++;}
+ if(FP2SCRATCH) {regscratch[fp2]=1;fscratch++;}
+
+ if(NOA4) regsa[5]=1;
+ if(GAS){
+ codename="\t.text\n";
+ bssname="";
+ dataname="\t.data\n";
+ if(use_sd) regsa[5]=1;
+ }else{
+ codename="\tsection\t\"CODE\",code\n";
+ if(use_sd){
+ /* preparing small data */
+ regsa[5]=1;
+ bssname= "\tsection\t\"__MERGED\",bss\n";
+ dataname="\tsection\t\"__MERGED\",data\n";
+ }else{
+ bssname= "\tsection\t\"BSS\",bss\n";
+ dataname="\tsection\t\"DATA\",data\n";
+ }
+ }
+ m_dataname=dataname;
+ m_bssname=bssname;
+ /* a5 can be used if no framepointer is used. */
+ if(!USEFRAMEPOINTER){ regsa[fbp]=0;/*fbp=sp;*/}
+ if(DEBUG&1) printf("CPU=%ld FPU=%ld\n",CPU,FPU);
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+#ifdef M68K_16BIT_INT
+ t_min[INT]=t_min(SHORT);
+#else
+ t_min[INT]=t_min(LONG);
+#endif
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[LONG]=ul2zum(2147483647UL);
+#ifdef M68K_16BIT_INT
+ t_max[INT]=t_max(SHORT);
+#else
+ t_max[INT]=t_max(LONG);
+#endif
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[LONG]=ul2zum(4294967295UL);
+#ifdef M68K_16BIT_INT
+ tu_max[INT]=t_max(UNSIGNED|SHORT);
+#else
+ tu_max[INT]=t_max(UNSIGNED|LONG);
+#endif
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+#ifdef M68K_16BIT_INT
+ stackalign=2;
+#endif
+
+ if(FLOAT64){
+ sizetab[FLOAT]=sizetab[DOUBLE];
+ align[FLOAT]=malign[DOUBLE];
+ }
+
+ marray[0]="__section(x)=__vattr(\"section(\"#x\")\")";
+ marray[1]="__M68K__";
+
+ if(CPU>=68000&&CPU<69000)
+ sprintf(cpu_macro,"__M%ld=1",CPU);
+ else
+ sprintf(cpu_macro,"__COLDFIRE=1");
+ marray[2]=cpu_macro;
+
+#ifdef M68K_16BIT_INT
+ marray[3]="__INTSIZE=16";
+#else
+ marray[3]="__INTSIZE=32";
+#endif
+
+ marray[4]="__stdargs=__attr(\"__stdargs;\")";
+ marray[5]="__regargs=__attr(\"__regargs;\")";
+ marray[6]="__vbccargs=__attr(\"__vbccargs;\")";
+ marray[7]="__fp0ret=__attr(\"__fp0ret;\")";
+ if(SMALLDATA)
+ marray[8]="__SMALL_DATA__";
+ else
+ marray[8]="__LARGE_DATA__";
+
+ if(FPU==68881){
+ sprintf(fpu_macro,"__M68881=1");
+ marray[9]=fpu_macro;
+ }else if(FPU>68000&&FPU<69000){
+ sprintf(fpu_macro,"__M68882=1");
+ marray[9]=fpu_macro;
+ }else
+ marray[9]=0;
+ marray[10]=0;
+ target_macros=marray;
+
+ if(AMI_SOFTFLOAT&&!optsize){
+ declare_builtin("_ieeeaddl",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-66));
+ declare_builtin("_ieeesubl",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-72));
+ declare_builtin("_ieeemull",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-78));
+ declare_builtin("_ieeedivl",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-84));
+ declare_builtin("_ieeenegl",FLOAT,FLOAT,d0,0,0,1,ami_ieee("SingBas",-60));
+ declare_builtin("_ieeeaddd",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-66));
+ declare_builtin("_ieeesubd",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-72));
+ declare_builtin("_ieeemuld",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-78));
+ declare_builtin("_ieeedivd",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-84));
+ declare_builtin("_ieeenegd",DOUBLE,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-60));
+ declare_builtin("_ieees2d",DOUBLE,FLOAT,d0,0,0,1,ami_ieee("DoubTrans",-108));
+ declare_builtin("_ieeed2s",FLOAT,DOUBLE,d0d1,0,0,1,ami_ieee("DoubTrans",-102));
+ declare_builtin("_ieeefltsl",FLOAT,LONG,d0,0,0,1,ami_ieee("SingBas",-36));
+ declare_builtin("_ieeefltsd",DOUBLE,LONG,d0,0,0,1,ami_ieee("DoubBas",-36));
+ declare_builtin("_ieeefltul",FLOAT,UNSIGNED|LONG,0,0,0,1,0);
+ declare_builtin("_ieeefltud",DOUBLE,UNSIGNED|LONG,0,0,0,1,0);
+ declare_builtin("_ieeefixlsl",LONG,FLOAT,d0,0,0,1,ami_ieee("SingBas",-30));
+ declare_builtin("_ieeefixlsw",SHORT,FLOAT,d0,0,0,1,ami_ieee("SingBas",-30));
+ declare_builtin("_ieeefixlsb",CHAR,FLOAT,d0,0,0,1,ami_ieee("SingBas",-30));
+ declare_builtin("_ieeefixdsl",LONG,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-30));
+ declare_builtin("_ieeefixdsw",SHORT,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-30));
+ declare_builtin("_ieeefixdsb",CHAR,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-30));
+ declare_builtin("_ieeefixlul",UNSIGNED|LONG,FLOAT,0,0,0,1,0);
+ declare_builtin("_ieeefixluw",UNSIGNED|SHORT,FLOAT,0,0,0,1,0);
+ declare_builtin("_ieeefixlub",UNSIGNED|CHAR,FLOAT,0,0,0,1,0);
+ declare_builtin("_ieeefixdul",UNSIGNED|LONG,DOUBLE,0,0,0,1,0);
+ declare_builtin("_ieeefixduw",UNSIGNED|SHORT,DOUBLE,0,0,0,1,0);
+ declare_builtin("_ieeefixdub",UNSIGNED|CHAR,DOUBLE,0,0,0,1,0);
+ declare_builtin("_ieeecmpl",INT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-42));
+ declare_builtin("_ieeecmpd",INT,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-42));
+#if 0
+ declare_builtin("_ieeecmpllt",INT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("_ieeecmplle",INT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("_ieeecmplgt",INT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("_ieeecmplge",INT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("_ieeecmpleq",INT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("_ieeecmplneq",INT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("_ieeecmpdlt",INT,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("_ieeecmpdle",INT,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("_ieeecmpdgt",INT,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("_ieeecmpdge",INT,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("_ieeecmpdeq",INT,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("_ieeecmpdneq",INT,DOUBLE,0,DOUBLE,0,1,0);
+#endif
+ declare_builtin("_ieeetstl",INT,FLOAT,d0,0,0,1,ami_ieee("SingBas",-48));
+ declare_builtin("_ieeetstd",INT,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-48));
+ declare_builtin("_flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
+ declare_builtin("_flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
+ declare_builtin("_flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
+ declare_builtin("_flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);
+ declare_builtin("_sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
+ declare_builtin("_sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
+ declare_builtin("_uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
+ declare_builtin("_uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
+ }else{
+ int pd0,pd1,pd0d1;
+ if(VBCCCALL){
+ pd0=d0;pd1=d1;pd0d1=d0d1;
+ }else{
+ pd0=pd1=pd0d1=0;
+ }
+
+ declare_builtin("_ieeeaddl",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0);
+ declare_builtin("_ieeesubl",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0);
+ declare_builtin("_ieeemull",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0);
+ declare_builtin("_ieeedivl",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0);
+ declare_builtin("_ieeenegl",FLOAT,FLOAT,pd0,0,0,1,0);
+ declare_builtin("_ieeeaddd",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0);
+ declare_builtin("_ieeesubd",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0);
+ declare_builtin("_ieeemuld",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0);
+ declare_builtin("_ieeedivd",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0);
+ declare_builtin("_ieeenegd",DOUBLE,DOUBLE,pd0d1,0,0,1,0);
+ declare_builtin("_ieees2d",DOUBLE,FLOAT,pd0,0,0,1,0);
+ declare_builtin("_ieeed2s",FLOAT,DOUBLE,pd0d1,0,0,1,0);
+ declare_builtin("_ieeefltsl",FLOAT,LONG,pd0,0,0,1,0);
+ declare_builtin("_ieeefltsd",DOUBLE,LONG,pd0,0,0,1,0);
+ declare_builtin("_ieeefltul",FLOAT,UNSIGNED|LONG,pd0,0,0,1,0);
+ declare_builtin("_ieeefltud",DOUBLE,UNSIGNED|LONG,pd0,0,0,1,0);
+ declare_builtin("_ieeefixlsl",LONG,FLOAT,pd0,0,0,1,0);
+ declare_builtin("_ieeefixlsw",SHORT,FLOAT,pd0,0,0,1,0);
+ declare_builtin("_ieeefixlsb",CHAR,FLOAT,pd0,0,0,1,0);
+ declare_builtin("_ieeefixdsl",LONG,DOUBLE,pd0d1,0,0,1,0);
+ declare_builtin("_ieeefixdsw",SHORT,DOUBLE,pd0d1,0,0,1,0);
+ declare_builtin("_ieeefixdsb",CHAR,DOUBLE,pd0d1,0,0,1,0);
+ declare_builtin("_ieeefixlul",UNSIGNED|LONG,FLOAT,pd0,0,0,1,0);
+ declare_builtin("_ieeefixluw",UNSIGNED|SHORT,FLOAT,pd0,0,0,1,0);
+ declare_builtin("_ieeefixlub",UNSIGNED|CHAR,FLOAT,pd0,0,0,1,0);
+ declare_builtin("_ieeefixdul",UNSIGNED|LONG,DOUBLE,pd0d1,0,0,1,0);
+ declare_builtin("_ieeefixduw",UNSIGNED|SHORT,DOUBLE,pd0d1,0,0,1,0);
+ declare_builtin("_ieeefixdub",UNSIGNED|CHAR,DOUBLE,pd0d1,0,0,1,0);
+ declare_builtin("_ieeefixdub",UNSIGNED|CHAR,DOUBLE,pd0d1,0,0,1,0);
+ declare_builtin("_ieeecmpl",INT,FLOAT,pd0,FLOAT,pd1,1,0);
+ declare_builtin("_ieeecmpd",INT,DOUBLE,pd0d1,DOUBLE,0,1,0);
+#if 0
+ declare_builtin("_ieeecmpllt",INT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("_ieeecmplle",INT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("_ieeecmplgt",INT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("_ieeecmplge",INT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("_ieeecmpleq",INT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("_ieeecmplneq",INT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("_ieeecmpdlt",INT,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("_ieeecmpdle",INT,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("_ieeecmpdgt",INT,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("_ieeecmpdge",INT,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("_ieeecmpdeq",INT,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("_ieeecmpdneq",INT,DOUBLE,0,DOUBLE,0,1,0);
+#endif
+ declare_builtin("_ieeetstl",INT,FLOAT,pd0,0,0,1,0);
+ declare_builtin("_ieeetstd",INT,DOUBLE,pd0d1,0,0,1,0);
+ declare_builtin("_flt32tosint64",LLONG,FLOAT,pd0,0,0,1,0);
+ declare_builtin("_flt64tosint64",LLONG,DOUBLE,pd0d1,0,0,1,0);
+ declare_builtin("_flt32touint64",UNSIGNED|LLONG,FLOAT,pd0,0,0,1,0);
+ declare_builtin("_flt64touint64",UNSIGNED|LLONG,DOUBLE,pd0d1,0,0,1,0);
+ declare_builtin("_sint64toflt32",FLOAT,LLONG,pd0d1,0,0,1,0);
+ declare_builtin("_sint64toflt64",DOUBLE,LLONG,pd0d1,0,0,1,0);
+ declare_builtin("_uint64toflt32",FLOAT,UNSIGNED|LLONG,pd0d1,0,0,1,0);
+ declare_builtin("_uint64toflt64",DOUBLE,UNSIGNED|LLONG,pd0d1,0,0,1,0);
+ }
+ {
+ char *asm;
+ declare_builtin("_divs",LONG,LONG,d0,LONG,d1,1,0);
+ declare_builtin("_divu",LONG,LONG,d0,LONG,d1,1,0);
+#define SMODS "\tjsr\t__divs\n\tmove.l\td1,d0"
+#define SMODU "\tjsr\t__divu\n\tmove.l\td1,d0"
+ asm=mymalloc(strlen(SMODS)+1);
+ strcpy(asm,SMODS);
+ declare_builtin("_mods",LONG,LONG,d0,LONG,d1,1,asm);
+ asm=mymalloc(strlen(SMODU)+1);
+ strcpy(asm,SMODU);
+ declare_builtin("_modu",LONG,LONG,d0,LONG,d1,1,asm);
+ }
+ declare_builtin("_lshint64",LLONG,LLONG,0,INT,0,1,0);
+ declare_builtin("_rshsint64",LLONG,LLONG,0,INT,0,1,0);
+ declare_builtin("_rshuint64",(UNSIGNED|LLONG),(UNSIGNED|LLONG),0,INT,0,1,0);
+
+ return 1;
+}
+
+int freturn(type *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+{
+ long l;int tu=t->flags&NQ;
+ if(t->attr&&ISFLOAT(tu)&&FPU>68000&&strstr(t->attr,"__fp0ret;")) return fp0;
+ if(tu==FLOAT&&FLOAT64) tu+=DOUBLE-FLOAT;
+ if(tu==FLOAT){
+ if(FPU>68000&&!NOFPRETURN)
+ return fp0;
+ else
+ return d0;
+ }
+ if(tu==DOUBLE||tu==LDOUBLE){
+ if(FPU>68000&&!NOFPRETURN){
+ return fp0;
+ }else{
+ if(NOMREGRETURN) return 0;
+#if NEW_RET
+ return d0d1;
+#else
+ return d0;
+#endif
+ }
+ }
+ if(tu==STRUCT||tu==UNION){
+ if(!NOMREGRETURN){
+ l=zm2l(szof(t));
+#if NEW_RET
+ if(l==4) return d0;
+ if(l==8) return d0d1;
+ /* alte Variante; unschoen */
+ if(l==12) return d0;
+ if(l==16) return d0;
+#else
+ if(l==4||l==8||l==12||l==16) return d0;
+#endif
+ }
+ return 0;
+ }
+ if(tu==LLONG)
+ return d0d1;
+ if(zmleq(szof(t),l2zm(4L))) return d0; else return 0;
+}
+int cost_savings(IC *p,int r,obj *o)
+{
+ int c=p->code;
+ if((r==a6||r==d7||r==d6d7||r==fp7)&&!RESERVEREGS) return -1;
+ if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+ if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+ if(o->flags&VKONST){
+ int t;
+ if(CPU==68040) return 0;
+ t=o->v->ctyp&NQ;
+ if(ISFLOAT(t)) return 2;
+ if(t==CHAR&&r>=a0&&r<=a7) return 0/*INT_MIN*/;
+ if(t==LLONG) return 0;
+ if(cf&&(t<INT)&&p->q2.flags) return 0/*INT_MIN*/;
+ eval_const(&o->v->cobj.val,t);
+ if(zmeqto(vmax,Z0)) return 0;
+ if(o->flags&DREFOBJ) return 2;
+ if((p->code==ASSIGN&&o==&p->q1)||p->code==PUSH||p->code==SETRETURN){
+ if(p->code==PUSH||(p->z.flags&DREFOBJ)||
+ ((p->z.flags&VAR)&&(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN))){
+ if(r>=d0&&r<=d7)
+ return 2;
+ else
+ return 1;
+ }
+ return 0;
+ }
+ if(c==ADDI2P||c==SUBIFP){
+ if(zmleq(vmax,l2zm(32767L))&&zmleq(l2zm(-32768L),vmax)) return 0;
+ if(r>=d0&&r<=d7)
+ return 3;
+ return CPU<68020?1:0;
+ }
+ if(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==SUBPFP){
+ if(zmleq(vmax,l2zm(8L))&&zmleq(l2zm(-8L),vmax)) return 0;
+ if(p->flags&EFF_IC) return 0;
+ if(r>=d0&&r<=d7)
+ return 2;
+ else
+ return 1;
+ }
+ if(c==COMPARE){
+ if(r>=d0&&r<=d7)
+ return 2;
+ else
+ return 1;
+ }
+ if(r>=a0&&r<=a7) return INT_MIN;
+ /* TODO: which allocations are useful? */
+ return 0;
+ }
+ if(o->flags&DREFOBJ){
+ if(r>=a0&&r<=a7){
+ return 4;
+ }
+ }
+ if((c==ADDI2P||c==SUBIFP||c==ADDRESS)&&(o==&p->q1||o==&p->z)&&r>=a0&&r<=a7){
+ return 4;
+ }
+ if(r>=a0&&r<=a7){
+ if(o->flags&DREFOBJ) ierror(0);
+ if(c!=GETRETURN&&c!=SETRETURN&&c!=ASSIGN&&c!=PUSH&&c!=TEST&&c!=COMPARE&&c!=CONVERT){
+ if(c==ADDI2P||c==SUBIFP){
+ if(o==&p->q2)
+ return INT_MIN;
+ }else if(c==SUBPFP){
+ if(o==&p->z)
+ return INT_MIN;
+ }else{
+ return INT_MIN;
+ }
+ }
+ if(c==CONVERT&&((p->typf&NQ)==CHAR||(p->typf2&NQ)==CHAR||ISFLOAT(p->typf)||ISFLOAT(p->typf2)))
+ return INT_MIN;
+ }
+
+ if(c==TEST&&r>=d0&&r<=d7){
+ return 3;
+ }
+ if(o==&p->z&&(p->q1.flags&VKONST)){
+ eval_const(&p->q1.v->cobj.val,p->q1.v->ctyp&NQ);
+ if(zmleq(vmax,l2zm(127L))&&zmleq(l2zm(-128L),vmax)&&r>=d0&&r<=d7)
+ return 3;
+ }
+ return 2;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(r==0) return 0;
+ t&=NQ;
+ if(ISFLOAT(t)){
+ if(FPU>68000){
+ if(r>=fp0&&r<=fp7) return(1); else return 0;
+ }else{
+ if(t==FLOAT&&!FLOAT64)
+ return (r>=d0&&r<=d7);
+ else
+ return (r>=25&&r<=28);
+ }
+ }
+ if(t==POINTER&&mode<=0&&r>=d0&&r<=d7) return 1;
+ if(t==POINTER&&r>=1&&r<=8) return 1;
+ if(t>=CHAR&&t<=LONG){
+ if((r>=d0&&r<=d7)||(mode==-1&&t>=SHORT&&r>=1&&r<=8)) return 1;
+ }
+ if(t==LLONG&&r>=25&&r<=28) return 1;
+ return 0;
+}
+
+int dangerous_IC(IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+{
+ int op=o&NQ,tp=t&NQ;
+ /* All pointers have the same representation. */
+ if(tp==POINTER&&op==POINTER) return 0;
+ /* Pointer and int/long as well */
+ if(const_expr){
+#ifdef M68K_16BIT_INT
+ if(tp==POINTER&&(op==LONG)) return 0;
+ if(op==POINTER&&(tp==LONG)) return 0;
+#else
+ if(tp==POINTER&&(op==INT||op==LONG)) return 0;
+ if(op==POINTER&&(tp==INT||tp==LONG)) return 0;
+#endif
+ }
+ /* Signed und Unsigned integers with the same size, too. */
+ if(op==tp) return 0;
+#ifdef M68K_16BIT_INT
+ /* int==short */
+ if((tp==INT&&op==SHORT)||(tp==SHORT&&op==INT)) return 0;
+#else
+ /* int==long */
+ if((tp==INT&&op==LONG)||(tp==LONG&&op==INT)) return 0;
+#endif
+ if(FLOAT64&&ISFLOAT(op)&&ISFLOAT(tp)) return 0;
+ /* long double==double */
+ if((op==DOUBLE||op==LDOUBLE)&&(tp==DOUBLE||tp==LDOUBLE)) return 0;
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,type *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ title(f);
+ if(GAS){
+ if(newobj&§ion!=SPECIAL)
+ emit(f,"%ld\n",zm2l(size));
+ else
+ emit(f,"\t.space\t%ld\n",zm2l(size));
+ newobj=0;
+ }else{
+ /*if(section!=BSS&§ion!=SPECIAL&&newobj){emit(f,bssname);if(f) section=BSS;}*/
+ emit(f,"\tds.b\t%ld\n",zm2l(size));newobj=0;
+ }
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ title(f);
+ if(zm2l(align)>1){
+ if(GAS){
+ emit(f,"\t.align\t4\n");
+ }else{
+ emit(f,"\tcnop\t0,4\n");
+ }
+ }
+}
+void gen_var_head(FILE *f,Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;
+ title(f);
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->tattr&(FAR|CHIP)){
+ if(v->tattr&CHIP){
+ dataname="\tsection\t\"CHIP_DATA\",data,chip\n";
+ bssname="\tsection\t\"CHIP_BSS\",bss,chip\n";
+ }else{
+ dataname="\tsection\t\"DATA\",data\n";
+ bssname="\tsection\t\"BSS\",bss\n";
+ }
+ if(f) section=-1;
+ }else{
+ dataname=m_dataname;
+ bssname=m_bssname;
+ }
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||CONSTINDATA/*||use_sd*/)&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!CONSTINDATA/*&&!use_sd*/&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(GAS){
+ if(section!=BSS) emit(f,"\t.align\t4\n%s%ld:\n",labprefix,zm2l(v->offset));
+ else emit(f,"\t.comm\t%s%ld,",labprefix,zm2l(v->offset));
+ }else{
+ emit(f,"\tcnop\t0,4\n%s%ld\n",labprefix,zm2l(v->offset));
+ }
+ newobj=1;
+ }
+ if(v->storage_class==EXTERN){
+ if(GAS){
+ emit(f,"\t.global\t%s%s\n",ISFUNC(v->vtyp->flags)?FUNCPREFIX(v->vtyp):idprefix,v->identifier);
+ }else{
+ emit(f,"\tpublic\t%s%s\n",ISFUNC(v->vtyp->flags)?FUNCPREFIX(v->vtyp):idprefix,v->identifier);
+ }
+ if(v->flags&(DEFINED|TENTATIVE)){
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||CONSTINDATA/*||use_sd*/)&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!CONSTINDATA/*&&!use_sd*/&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(GAS){
+ if(section!=BSS)
+ emit(f,"\t.align\t4\n%s%s:\n",idprefix,v->identifier);
+ else
+ emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+ }else{
+ emit(f,"\tcnop\t0,4\n%s%s\n",idprefix,v->identifier);
+ }
+ newobj=1;
+ }
+ }
+ if(v->tattr&(FAR|CHIP)) {if(f) section=-1;newobj=0;}
+}
+void gen_dc(FILE *f,int t,const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ char s;
+ title(f);
+ if(!p) ierror(0);
+/* if(section!=DATA){emit(f,dataname);if(f) section=DATA;}*/
+ if(ISFLOAT(t)||(t&NQ)==LLONG) s='l'; else s=x_t[t&NQ];
+ if(GAS){
+ char *str;
+ if(s=='b') str="\t.byte\t";
+ else if(s=='w') str="\t.short\t";
+ else if(s=='l') str="\t.long\t";
+ else ierror(0);
+ emit(f,"%s",str);
+ }else{
+ emit(f,"\tdc.%c\t",s);
+ }
+ if(!p->tree){
+ if(ISFLOAT(t)){
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;char *s;
+ ip=(unsigned char *)&p->val.vdouble;
+ if(GAS) s="0x"; else s="$";
+ emit(f,"%s%02x%02x%02x%02x",s,ip[0],ip[1],ip[2],ip[3]);
+ if((t&NQ)!=FLOAT){
+ emit(f,",%s%02x%02x%02x%02x",s,ip[4],ip[5],ip[6],ip[7]);
+ }
+ }else if((t&NQ)==LLONG){
+ zumax tmp;
+ eval_const(&p->val,t);
+ tmp=vumax;
+ vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff));
+ gval.vulong=zum2zul(vumax);
+ emitval(f,&gval,UNSIGNED|LONG);
+ emit(f,",");
+ vumax=zumand(tmp,ul2zum(0xffffffff));
+ gval.vulong=zum2zul(vumax);
+ emitval(f,&gval,UNSIGNED|LONG);
+ }else{
+ emitval(f,&p->val,t&NU);
+ }
+ }else{
+ int m,m2,m3;
+ p->tree->o.am=0;
+ m=p->tree->o.flags;
+ p->tree->o.flags&=~VARADR;
+ m2=g_flags[5];
+ g_flags[5]&=~USEDFLAG;
+ m3=use_sd;
+ use_sd=0;
+ emit_obj(f,&p->tree->o,t&NU);
+ p->tree->o.flags=m;
+ g_flags[5]=m2;
+ use_sd=m3;
+ }
+ emit(f,"\n");newobj=0;
+}
+
+static void allocreg(int r)
+{
+ if(reg_pair(r,&rp)){
+ regs[rp.r1]=1;
+ regs[rp.r2]=1;
+ }
+ regs[r]=1;
+}
+
+static void freereg(int r)
+{
+ if(reg_pair(r,&rp)){
+ regs[rp.r1]=0;
+ regs[rp.r2]=0;
+ }
+ regs[r]=0;
+}
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE *f,IC *p,Var *v,zmax offset)
+{
+ int c,t;char fp[2]="\0\0";
+ int act_line=0;char *act_file=0;
+ int shiftisdiv;
+ if(DEBUG&1) printf("gen_code()\n");
+ for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+ if(!NOPEEPHOLE){
+ /* Adressierungsarten benutzen */
+ if(!addressing(p)) offset=l2zm(0L);
+ }
+ title(f);
+ if(debug_info){
+ if(HUNKDEBUG){
+ if(!GAS){
+ act_line=1;
+ emit(f,"\tdsource\t\"%s\"\n",filename);
+ emit(f,"\tdebug\t%d\n",act_line);
+ }
+ }
+ }
+ reglabel=++label;freglabel=++label;
+ function_top(f,v,zm2l(offset));
+ cc_set=cc_set_tst=0;
+ stackoffset=notpopped=dontpop=maxpushed=0;
+ for(c=1;c<=MAXR;c++){
+ if(regsa[c]||regused[c]){
+ BSET(regs_modified,c);
+ }
+ }
+ for(;p;pr(f,p),p=p->next){
+ if(debug_info){
+ if(HUNKDEBUG){
+ if(p->file&&p->file!=act_file){
+ act_file=p->file;
+ if(!GAS) emit(f,"\tdsource\t\"%s\"\n",act_file);
+ }
+ if(p->line&&p->line!=act_line){
+ act_line=p->line;
+ if(!GAS) emit(f,"\tdebug\t%d\n",act_line);
+ }
+ }else{
+ dwarf2_line_info(f,p);
+ }
+ }
+
+ if(FLOAT64){
+ if(p->code==CONVERT)
+ if((q1typ(p)&NQ)==FLOAT) p->typf2+=DOUBLE-FLOAT;
+ if((ztyp(p)&NQ)==FLOAT) p->typf+=DOUBLE-FLOAT;
+ }
+
+ c=p->code;t=p->typf;
+ if(c==NOP) continue;
+ cc_set_tst=cc_set;
+ cc_typ_tst=cc_typ;
+ shiftisdiv=0;
+ if(cc_set_tst&&(DEBUG&512)){emit(f,"; cc_set_tst=");emit_obj(f,cc_set_tst,t);emit(f,"\n");}
+ if(cc_set&&(DEBUG&512)){emit(f,"; cc_set=");emit_obj(f,cc_set,t);emit(f,"\n");}
+ pushedreg&=16;if(c==RESTOREREGS) pushedreg=0;
+ if(DEBUG&256){emit(f,"; "); pric2(f,p);}
+ if(DEBUG&512) emit(f,"; stackoffset=%ld, notpopped=%ld, pushedreg=%d, dontpop=%ld\n",stackoffset,notpopped,pushedreg,dontpop);
+ /* muessen wir Argumente poppen? */
+ if(notpopped&&!dontpop){
+ int flag=0;
+ if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+ emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[notpopped<=8],strshort[notpopped<32768],notpopped,mregnames[sp]);
+ pop(notpopped);notpopped=0;/*cc_set_tst=cc_set=0;*/
+ }
+ }
+ /* na, ob das hier ok ist..? */
+ if(c==SUBPFP) c=SUB;
+ if(c==PMULT) c=MULT;
+ if(c==ALLOCREG){
+ allocreg(p->q1.reg);
+ continue;
+ }
+ if(c==FREEREG){
+ freereg(p->q1.reg);
+ continue;
+ }
+ if(c==LABEL){
+ if(debug_info&&HUNKDEBUG) act_line=0;
+ if(GAS){
+ emit(f,"%s%d:\n",labprefix,t);
+ }else{
+ emit(f,"%s%d\n",labprefix,t);
+ }
+ cc_set=0;continue;
+ }
+ if(c==BRA){emit(f,"\t%sbra\t%s%d\n",(GAS?"j":""),labprefix,t);continue;}
+ if(c>=BEQ&&c<BRA){
+ if(GAS){
+ if(stored_cc){emit(f,"\tjne\t%s%d\n",labprefix,t);stored_cc=0;continue;}
+ if((comptyp&UNSIGNED)||(comptyp&NQ)==POINTER){
+ emit(f,"\tj%s\t%s%d\n",ubranch[c-BEQ],labprefix,t);
+ }else{
+ emit(f,"\t%sj%s\t%s%d\n",fp,ename[c]+1,labprefix,t);
+ }
+ }else{
+ if(stored_cc){emit(f,"\tbne\t%s%d\n",labprefix,t);stored_cc=0;continue;}
+ if((comptyp&UNSIGNED)||(comptyp&NQ)==POINTER){
+ emit(f,"\tb%s\t%s%d\n",ubranch[c-BEQ],labprefix,t);
+ }else{
+ emit(f,"\t%s%s\t%s%d\n",fp,ename[c],labprefix,t);
+ }
+ }
+ continue;
+ }
+#if 0
+ if(CPU>=68020&&(c==LSHIFT||c==MULT)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&ISINT(p->typf)){
+ int l=0;
+ eval_const(&p->q2.val,q2typ(p));
+ if(c==LSHIFT&&zmeqto(vmax,l2zm(1L))) l=2;
+ if(c==LSHIFT&&zmeqto(vmax,l2zm(2L))) l=4;
+ if(c==LSHIFT&&zmeqto(vmax,l2zm(3L))) l=8;
+ if(c==MULT&&zmeqto(vmax,l2zm(2L))) l=2;
+ if(c==MULT&&zmeqto(vmax,l2zm(4L))) l=4;
+ if(c==MULT&&zmeqto(vmax,l2zm(8L))) l=8;
+ if(l!=0){
+ IC *p2=p->next;
+ while(p2&&(p2->code==ALLOCREG||p2->code==FREEREG)) p2=p2->next;
+ if((p2->code==ADD||p2->code==ADDI2P)&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==p->z.reg&&(p2->typf&NU)==(p->typf&NU)&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg>=a0&&p2->q1.reg<=a7&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg>=a0&&p2->z.reg<=a7){
+ IC *p3=p2->next;
+ while(p3&&p3->code==FREEREG) if(p3&&p3->q1.reg==p->z.reg) break;
+ if(p3&&p3->code==FREEREG&&p3->q1.reg==p->z.reg){
+ int r;
+ if(isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7)
+ r=p->q1.reg;
+ else{
+ move(f,&p->q1,0,0,p->z.reg,p->typf);
+ r=p->z.reg;
+ }
+ emit(f,"\tlea\t(%s,%s.%c*%d),%s\n",mregnames[p2->q1.reg],mregnames[r],sizetab[p->typf&NQ]==2?'w':'l',l,mregnames[p2->z.reg]);
+ p->code=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ continue;
+ }
+ }
+ }
+ }
+#endif
+ if(c==COMPARE&&isconst(q2)&&!cf&&(t&NQ)!=LLONG){
+ case_table *ct=calc_case_table(p,JUMP_TABLE_DENSITY);
+ IC *p2;
+ if(ct&&(ct->num>=JUMP_TABLE_LENGTH||(!isreg(q1)&&ct->num>=JUMP_TABLE_LENGTH/2))){
+ int r,defl,tabl=++label,rts=0,i,ar=0;
+ if(ct->next_ic->code==BRA)
+ defl=ct->next_ic->typf;
+ else
+ defl=++label;
+ for(r=d0;r<=d7;r++)
+ if(!regs[r]) break;
+ if(r>d7){
+ if((!(p->q1.flags®))||p->q1.reg!=d0)
+ r=d0;
+ else
+ r=d1;
+ emit(f,"\tsubq.%s\t#4,%s\n",cf?"l":"w",mregnames[sp]);
+ emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[r],mregnames[sp]);
+ push(8);
+ }else{
+ regused[r]=1;
+ BSET(regs_modified,r);
+ }
+ if(!regs[r]||(p->q1.flags&(REG|DREFOBJ))==DREFOBJ){
+ for(ar=1;ar<sp;ar++)
+ if(!regs[ar]) break;
+ if(ar>=sp){
+ ar=a0;
+ if(!regs[r]){
+ emit(f,"\tsubq.%s\t#4,%s\n",cf?"l":"w",mregnames[sp]);
+ push(4);
+ }
+ emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[ar],mregnames[sp]);
+ push(4);
+ }else{
+ regused[ar]=1;
+ BSET(regs_modified,ar);
+ }
+ }
+ if(regs[r]||(ar&®s[ar])) defl=++label;
+ if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==DREFOBJ){
+ p->q1.flags&=~DREFOBJ;
+ move(f,&p->q1,0,0,ar,POINTER);
+ p->q1.flags|=(REG|DREFOBJ);
+ p->q1.flags&=~VAR;
+ p->q1.reg=ar;
+ }
+ if((t&NU)==(UNSIGNED|CHAR))
+ emit(f,"\tmoveq\t#0,%s\n",mregnames[r]);
+ move(f,&p->q1,0,0,r,t);
+ if((t&NU)==CHAR){
+ emit(f,"\text.w\t%s\n",mregnames[r]);
+ t=SHORT;
+ }
+ if((t&NU)==(UNSIGNED|CHAR))
+ t=(UNSIGNED|SHORT);
+ if(((t&UNSIGNED)&&!zumeqto(ct->min.vumax,ul2zum(0UL)))||
+ (!(t&UNSIGNED)&&!zmeqto(ct->min.vmax,l2zm(0L)))){
+ emit(f,"\tsub.%c\t#",x_t[t&NQ]);
+ if(t&UNSIGNED)
+ emitzum(f,ct->min.vumax);
+ else
+ emitzm(f,ct->min.vmax);
+ emit(f,",%s\n",mregnames[r]);
+ }
+ emit(f,"\tcmp.%c\t#",x_t[t&NQ]);
+ emitzum(f,ct->diff);
+ emit(f,",%s\n",mregnames[r]);
+ if(regs[r]||regs[ar])
+ emit(f,"\tbhi\t%s%d\n",labprefix,++label);
+ else
+ emit(f,"\tbhi\t%s%d\n",labprefix,defl);
+ if(CPU<68020)
+ emit(f,"\tlsl.%c\t#2,%s\n",x_t[t&NQ],mregnames[r]);
+ for(i=MAXR;i>=1;i--)
+ if(regs[i]&4) rts=1;
+ if(regs[r]||regs[ar]){
+ int off;
+ if(regs[r]) off=4; else off=0;
+ if(ar&®s[ar]) off+=4;
+ if(CPU>=68020)
+ emit(f,"\tmove.l\t%s%d(%spc,%s.%c*4),%d(%s)\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],off,mregnames[sp]);
+ else
+ emit(f,"\tmove.l\t%s%d(%spc,%s.%c),%d(%s)\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],off,mregnames[sp]);
+ if(ar&®s[ar]){
+ emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[ar]);
+ pop(4);
+ }
+ if(regs[r]){
+ emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[r]);
+ pop(4);
+ }
+ emit(f,"\trts\n");
+ pop(4);
+ }else{
+ if(CPU>=68020)
+ emit(f,"\tmove.l\t%s%d(%spc,%s.%c*4),%s\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],mregnames[ar]);
+ else
+ emit(f,"\tmove.l\t%s%d(%spc,%s.%c),%s\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],mregnames[ar]);
+ emit(f,"\tjmp\t(%s)\n",mregnames[ar]);
+ }
+ if(GAS){
+ emit(f,"\t.align\t2\n");
+ emit(f,"%s%d:\n",labprefix,tabl);
+ emit_jump_table(f,ct,"\t.long\t","l",defl);
+ }else{
+ emit(f,"\tcnop\t0,4\n");
+ emit(f,"%s%d\n",labprefix,tabl);
+ emit_jump_table(f,ct,"\tdc.l\t","l",defl);
+ }
+ if(ct->next_ic->code!=BRA||regs[r]||(ar&®s[ar])){
+ if(regs[r]||(ar&®s[ar])){
+ emit(f,"%s%d%s\n",labprefix,label,GAS?":":"");
+ if(ar&®s[ar])
+ emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[ar]);
+ if(regs[r])
+ emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[r]);
+ emit(f,"\taddq.%c\t#4,%s\n",cf?'l':'w',mregnames[sp]);
+ }
+ emit(f,"%s%d%s\n",labprefix,defl,GAS?":":"");
+ p2=ct->next_ic->prev;
+ }else
+ p2=ct->next_ic;
+ if(p->prev) p=p->prev;
+ do{
+ p=p->next;
+ if(p->code==ALLOCREG)
+ allocreg(p->q1.reg);
+ if(p->code==FREEREG)
+ freereg(p->q1.reg);
+ }while(p!=p2);
+ continue;
+ }
+ }
+ if(p->q1.am){
+ if(!regs[p->q1.am->basereg]){
+ pric2(stdout,p);printf("%s\n",mregnames[p->q1.am->basereg]); ierror(0);
+ }
+ if(p->q1.am->dreg&&!regs[p->q1.am->dreg&127]){
+ printf("Register %s:\n",mregnames[p->q1.am->dreg&127]);
+ ierror(0);
+ }
+ }
+ if(p->q2.am){
+ if(!regs[p->q2.am->basereg]) {pric2(stdout,p);ierror(0);}
+ if(p->q2.am->dreg&&!regs[p->q2.am->dreg&127]) {printf("Register %s:\n",mregnames[p->q2.am->dreg&127]);ierror(0);}
+ }
+ if(p->z.am){
+ if(!regs[p->z.am->basereg]) {pric2(stdout,p);printf("am=%p b=%s,i=%s,o=%ld,s=%d\n",(void*)p->z.am,mregnames[p->z.am->basereg],mregnames[p->z.am->dreg&127],p->z.am->dist,p->z.am->skal);ierror(0);}
+ if(p->z.am->dreg&&!regs[p->z.am->dreg&127]) {printf("Register %s:\n",mregnames[p->z.am->dreg&127]);ierror(0);}
+ }
+ if((p->q1.flags®)&&!regs[p->q1.reg]&&p->code!=MOVEFROMREG&&(!reg_pair(p->q1.reg,&rp)||!regs[rp.r1]||!regs[rp.r2])){
+ printf("Register %s:\n",mregnames[p->q1.reg]);pric2(stdout,p);terror("illegal use of register");}
+ if((p->q2.flags®)&&!regs[p->q2.reg]&&(!reg_pair(p->q2.reg,&rp)||!regs[rp.r1]||!regs[rp.r2])){printf("Register %s:\n",mregnames[p->q2.reg]);pric2(stdout,p);terror("illegal use of register");}
+ if((p->z.flags®)&&!regs[p->z.reg]&&p->code!=MOVETOREG&&(!reg_pair(p->z.reg,&rp)||!regs[rp.r1]||!regs[rp.r2])){printf("Register %s:\n",mregnames[p->z.reg]);if(reg_pair(p->z.reg,&rp)) printf("%s=%d %s=%d\n",regnames[rp.r1],regs[rp.r1],regnames[rp.r2],regs[rp.r2]);pric2(stdout,p);terror("illegal use of register");}
+ /* if((p->q2.flags®)&&(p->z.flags®)&&p->q2.reg==p->z.reg){pric2(stdout,p);ierror(0);}*/
+ /*if((p->q2.flags&VAR)&&(p->z.flags&VAR)&&p->q2.v==p->z.v&&compare_objects(&p->q2,&p->z)){pric2(stdout,p);ierror(0);}*/
+ /* COMPARE #0 durch TEST ersetzen (erlaubt, da tst alle Flags setzt) */
+ if(c==COMPARE&&isconst(q2)){
+ eval_const(&p->q2.val,t);
+ if(zmeqto(l2zm(0L),vmax)&&zumeqto(ul2zum(0UL),vumax)&&zldeqto(d2zld(0.0),vldouble)){
+ c=p->code=TEST;p->q2.flags=0;
+ }
+ }
+ if(c==COMPARE&&isconst(q1)){
+ eval_const(&p->q1.val,t);
+ if(zmeqto(l2zm(0L),vmax)&&zumeqto(ul2zum(0UL),vumax)&&zldeqto(d2zld(0.0),vldouble)){
+ IC *bp=p->next;int bc;
+ c=p->code=TEST;p->q1=p->q2;p->q2.flags=0;p->q2.am=0;
+ /* Nachfolgenden Branch umdrehen */
+ while(bp&&bp->code==FREEREG) bp=bp->next;
+ bc=bp->code;
+ if(!bp||bc<BEQ||bc>BGT) ierror(0);
+ if(bc==BLT) bp->code=BGT;
+ if(bc==BGT) bp->code=BLT;
+ if(bc==BLE) bp->code=BGE;
+ if(bc==BGE) bp->code=BLE;
+ }
+ }
+ /* gesetzte ConditionCodes merken */
+ if(p->z.flags&&(!isreg(z)||p->z.reg>=d0)&&(c!=CONVERT||!ISFLOAT(p->typf2))&&((!ISFLOAT(t))||FPU>68000)){
+ cc_set=&p->z;cc_typ=p->typf;
+ }else{
+ cc_set=0;
+ }
+ if(c==LEA){
+ if(!isreg(z)||p->z.reg>8) ierror(0);
+ emit(f,"\tlea\t");emit_obj(f,&p->q1,t);
+ emit(f,",%s\n",mregnames[p->z.reg]);
+ continue;
+ }
+ if(c==PEA){
+ emit(f,"\tpea\t");emit_obj(f,&p->q1,t);emit(f,"\n");
+ push(zm2l(p->q2.val.vmax));
+ dontpop+=zm2l(p->q2.val.vmax);
+ continue;
+ }
+ if(c==MOVEFROMREG){
+ if(p->q1.reg<fp0)
+ emit(f,"\tmove.l\t%s,",mregnames[p->q1.reg]);
+ else if(p->q1.reg<25)
+ emit(f,"\tfmove.x\t%s,",mregnames[p->q1.reg]);
+ else
+ emit(f,"\tmovem.l\t%s,",mregnames[p->q1.reg]);
+ emit_obj(f,&p->z,t);emit(f,"\n");
+ continue;
+ }
+ if(c==MOVETOREG){
+ if(p->z.reg<fp0)
+ emit(f,"\tmove.l\t");
+ else if(p->z.reg<25)
+ emit(f,"\tfmove.x\t");
+ else
+ emit(f,"\tmovem.l\t");
+ emit_obj(f,&p->q1,t);emit(f,",%s\n",mregnames[p->z.reg]);
+ continue;
+ }
+ if(NOPEEPHOLE){
+ if(p->q1.am||p->q2.am||p->z.am){
+ ierror(0);
+ p->q1.am=p->q2.am=p->z.am=0;
+ }
+ }
+ p=do_refs(f,p);
+ if((p->q1.flags&&(q1typ(p)&NQ)==LLONG)||(p->q2.flags&&(q2typ(p)&NQ)==LLONG&&p->code!=LSHIFT&&p->code!=RSHIFT)||(p->z.flags&&(ztyp(p)&NQ)==LLONG)){
+ if(handle_llong(f,p)){
+ *fp=0;
+ continue;
+ }
+ }
+ if(NOPEEPHOLE){
+ if(p->q1.am||p->q2.am||p->z.am){
+ ierror(0);
+ p->q1.am=p->q2.am=p->z.am=0;
+ }
+ }
+#ifdef M68K_16BIT_INT
+ if(c==CONVERT&&((t&NQ)==LONG||(t&NQ)==POINTER)&&((p->typf2&NQ)==LONG||(p->typf2&NQ)==POINTER)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[LONG];
+ }
+#else
+ if(c==CONVERT&&((t&NQ)==LONG||(t&NQ)==INT||(t&NQ)==POINTER)&&((p->typf2&NQ)==LONG||(p->typf2&NQ)==INT||(p->typf2&NQ)==POINTER)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[LONG];
+ }
+#endif
+ if(c==CONVERT){
+ int to;
+ if((t&NQ)==POINTER) t=(UNSIGNED|LONG);
+ if((t&NQ)==LDOUBLE) t=DOUBLE;
+ to=p->typf2&NU;
+ if(to==POINTER) to=UNSIGNED|LONG;
+ if(to==LDOUBLE) to=DOUBLE;
+#ifdef M68K_16BIT_INT
+ if((to==(UNSIGNED|CHAR)||to==(UNSIGNED|SHORT)||to==(UNSIGNED|INT))&&!(t&UNSIGNED)&&(t&NQ)>(to&NQ))
+ cc_set=0;
+#else
+ if((to==(UNSIGNED|CHAR)||to==(UNSIGNED|SHORT))&&!(t&UNSIGNED)&&(t&NQ)>(to&NQ))
+ cc_set=0;
+#endif
+ if(ISFLOAT(t)||ISFLOAT(to)){
+ if(FPU>68000){
+ int zreg=0,freg=0;
+ if(ISFLOAT(t)&&ISFLOAT(to)){
+ if(isreg(q1)&&isreg(z)){
+ if(p->q1.reg!=p->z.reg)
+ emit(f,"\tfmove.x\t%s,%s\n",mregnames[p->q1.reg],mregnames[p->z.reg]);
+ continue;
+ }
+ }
+ if(isreg(z)&&p->z.reg>=fp0)
+ zreg=p->z.reg;
+ if(isreg(q1)&&p->q1.reg>=fp0){
+ if(!zreg&&(t&UNSIGNED)&&!ISHWORD(t))
+ zreg=p->q1.reg;
+ else
+ zreg=freg=get_reg(f,2,p,1);}
+ if(!zreg) zreg=freg=get_reg(f,2,p,0);
+ if((to&UNSIGNED)&&x_t[to&NQ]!='l'){
+ int dreg=get_reg(f,1,p,0);
+ emit(f,"\tmoveq\t#0,%s\n",mregnames[dreg]);
+ move(f,&p->q1,0,0,dreg,to);
+ move(f,0,dreg,0,zreg,LONG);
+ }else{
+ if(!isreg(q1)||p->q1.reg!=zreg)
+ move(f,&p->q1,0,0,zreg,to);
+ }
+ if(!ISFLOAT(t)){
+ if((t&UNSIGNED)&&!ISHWORD(t)){
+ char *s;
+ int dreg1,dreg2;
+ int l1=++label,l2=++label;
+ if(GAS) s="0x"; else s="$";
+ if(isreg(z))
+ dreg1=p->z.reg;
+ else
+ dreg1=get_reg(f,1,p,0);
+ if(FPU==68040)
+ dreg2=get_reg(f,1,p,0);
+ if(!freg){
+ if(!(isreg(q1)&&p->next&&p->next->code==FREEREG&&p->next->q1.reg==zreg)){
+ freg=get_reg(f,2,p,1);
+ emit(f,"\tfmove.x\t%s,%s\n",mregnames[zreg],mregnames[freg]);
+ zreg=freg;
+ }
+ }
+ emit(f,"\tfcmp.d\t#%s41e0000000000000,%s\n",s,mregnames[zreg]);
+ emit(f,"\tfbge\t%s%d\n",labprefix,l1);
+ if(FPU==68040){
+ emit(f,"\tfmove.l\t%sfpcr,%s\n",rprefix,mregnames[dreg2]);
+ emit(f,"\tmoveq\t#16,%s\n",mregnames[dreg1]);
+ emit(f,"\tor.l\t%s,%s\n",mregnames[dreg2],mregnames[dreg1]);
+ emit(f,"\tand.w\t#-33,%s\n",mregnames[dreg1]);
+ emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg1],rprefix);
+ }else{
+ emit(f,"\tfintrz\t%s\n",mregnames[zreg]);
+ }
+ emit(f,"\tfmove.l\t%s,%s\n",mregnames[zreg],mregnames[dreg1]);
+ emit(f,"\tbra\t%s%d\n",labprefix,l2);
+ emit(f,"%s%d:\n",labprefix,l1);
+ emit(f,"\tfsub.d\t#%s41e0000000000000,%s\n",s,mregnames[zreg]);
+ if(FPU==68040){
+ emit(f,"\tfmove.l\t%sfpcr,%s\n",rprefix,mregnames[dreg2]);
+ emit(f,"\tmoveq\t#16,%s\n",mregnames[dreg1]);
+ emit(f,"\tor.l\t%s,%s\n",mregnames[dreg2],mregnames[dreg1]);
+ emit(f,"\tand.w\t#-33,%s\n",mregnames[dreg1]);
+ emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg1],rprefix);
+ }else{
+ emit(f,"\tfintrz\t%s\n",mregnames[zreg]);
+ }
+ emit(f,"\tfmove.l\t%s,%s\n",mregnames[zreg],mregnames[dreg1]);
+ emit(f,"\tbchg\t#31,%s\n",mregnames[dreg1]);
+ emit(f,"%s%d:\n",labprefix,l2);
+ if(FPU==68040)
+ emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg2],rprefix);
+ move(f,0,dreg1,&p->z,0,t);
+ continue;
+ }
+ /* nach integer, d.h. Kommastellen abschneiden */
+ if(FPU==68040/*||FPU==68060*/){
+ /* bei 040 emuliert */
+ int dreg1,dreg2;
+ if(!NOINTZ){
+ if(isreg(z))
+ dreg1=p->z.reg;
+ else
+ dreg1=get_reg(f,1,p,0);
+ dreg2=get_reg(f,1,p,0);
+ emit(f,"\tfmove.l\t%sfpcr,%s\n",rprefix,mregnames[dreg2]);
+ emit(f,"\tmoveq\t#16,%s\n",mregnames[dreg1]);
+ emit(f,"\tor.l\t%s,%s\n",mregnames[dreg2],mregnames[dreg1]);
+ emit(f,"\tand.w\t#-33,%s\n",mregnames[dreg1]);
+ emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg1],rprefix);
+ }else{
+ dreg1=get_reg(f,1,p,0);
+ }
+ if((t&UNSIGNED)&&ISHWORD(t)){
+ emit(f,"\tfmove.l\t%s,%s\n",mregnames[zreg],mregnames[dreg1]);
+ emit(f,"\tmove.%c\t%s,",x_t[t&NQ],mregnames[dreg1]);
+ }else{
+ emit(f,"\tfmove.%c\t%s,",x_t[t&NQ],mregnames[zreg]);
+ }
+ emit_obj(f,&p->z,t);emit(f,"\n");
+ if(!NOINTZ)
+ emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg2],rprefix);
+ continue;
+ }else{
+ if(!NOINTZ){
+ if(!isreg(q1)||p->q1.reg!=zreg){
+ emit(f,"\tfintrz.x\t%s\n",mregnames[zreg]);
+ }else{
+ int nreg=get_reg(f,2,p,1);
+ emit(f,"\tfintrz.x\t%s,%s\n",mregnames[zreg],mregnames[nreg]);
+ zreg=nreg;
+ }
+ }
+ if((t&UNSIGNED)&&ISHWORD(t)){
+ int r;
+ if(isreg(z)) r=p->z.reg; else r=get_reg(f,1,p,0);
+ move(f,0,zreg,0,r,LONG);
+ move(f,0,r,&p->z,0,t);
+ }else{
+ move(f,0,zreg,&p->z,0,t);
+ }
+ continue;
+ }
+ }
+ if((to&UNSIGNED)&&x_t[to&NQ]=='l'){
+ int nlabel;
+ emit(f,"\ttst.%c\t",x_t[to&NQ]);
+ emit_obj(f,&p->q1,to);emit(f,"\n");
+ nlabel=++label;
+ emit(f,"\tbge.s\t%s%d\n",labprefix,nlabel);
+ emit(f,"\tfadd.d\t#4294967296,%s\n",mregnames[zreg]);
+ emit(f,"%s%d:\n",labprefix,nlabel);
+ }
+ if(!(p->z.reg)||p->z.reg!=zreg){
+ move(f,0,zreg,&p->z,0,t);
+ }
+ }else{
+ cc_set=0;
+ if((to&NQ)==(t&NQ)){
+ assign(f,p,&p->q1,&p->z,ASSIGN,sizetab[to&NQ],t);
+ continue;
+ }
+ if((to&NQ)==FLOAT&&((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)){
+ if(!OLD_SOFTFLOAT)
+ ierror(0);
+ saveregs(f,p);
+ assign(f,p,&p->q1,0,PUSH,msizetab[FLOAT],FLOAT);
+ scratch_modified();
+ if(GAS){
+ emit(f,"\t.global\t__ieees2d\n\tjbsr\t__ieees2d\n\taddq.%s\t#4,%s\n",strshort[1],mregnames[sp]);
+ }else{
+ emit(f,"\tpublic\t__ieees2d\n\tjsr\t__ieees2d\n\taddq.%s\t#4,%s\n",strshort[1],mregnames[sp]);
+ }
+ pop(4);
+ restoreregsa(f,p);
+ stored0d1(f,&p->z,t);
+ restoreregsd(f,p);
+ continue;
+ }
+ if(((to&NQ)==DOUBLE||(to&NQ)==LDOUBLE)&&(t&NQ)==FLOAT){
+ if(!OLD_SOFTFLOAT) ierror(0);
+ saveregs(f,p);
+ assign(f,p,&p->q1,0,PUSH,msizetab[DOUBLE],DOUBLE);
+ scratch_modified();
+ if(GAS){
+ emit(f,"\t.global\t__ieeed2s\n\tjbsr\t__ieeed2s\n\taddq.%s\t#8,%s\n",strshort[1],mregnames[sp]);
+ }else{
+ emit(f,"\tpublic\t__ieeed2s\n\tjsr\t__ieeed2s\n\taddq.%s\t#8,%s\n",strshort[1],mregnames[sp]);
+ }
+ pop(8);
+ restoreregsa(f,p);
+ move(f,0,d0,&p->z,0,t);
+ restoreregsd(f,p);
+ continue;
+ }
+ if(ISFLOAT(to)){
+ int uns;
+ if(!OLD_SOFTFLOAT) ierror(0);
+ saveregs(f,p);
+ if(t&UNSIGNED) uns='u'; else uns='s';
+ assign(f,p,&p->q1,0,PUSH,sizetab[to&NQ],to);
+ scratch_modified();
+ if(GAS){
+ emit(f,"\t.global\t__ieeefix%c%c\n\tjbsr\t__ieeefix%c%c\n\taddq.%s\t#%ld,%s\n",x_t[to&NQ],uns,x_t[to&NQ],uns,strshort[1],zm2l(sizetab[to&NQ]),mregnames[sp]);
+ }else{
+ emit(f,"\tpublic\t__ieeefix%c%c\n\tjsr\t__ieeefix%c%c\n\taddq.%s\t#%ld,%s\n",x_t[to&NQ],uns,x_t[to&NQ],uns,strshort[1],zm2l(sizetab[to&NQ]),mregnames[sp]);
+ }
+ pop(sizetab[to&NQ]);
+ restoreregsa(f,p);
+ move(f,0,d0,&p->z,0,t);
+ restoreregsd(f,p);
+ continue;
+ }else{
+ int uns,xt=x_t[to&NQ];
+ if(!OLD_SOFTFLOAT) ierror(0);
+ saveregs(f,p);
+ if(to&UNSIGNED) uns='u'; else uns='s';
+ if(xt!='l'){
+ emit(f,"\tsubq.%s\t#4,%s\n",strshort[1],mregnames[sp]);
+ push(4);
+ }
+ emit(f,"\tmove.%c\t",xt);
+ emit_obj(f,&p->q1,to);
+ if(xt!='l')
+ emit(f,",(%s)\n",mregnames[sp]);
+ else{
+ emit(f,",-(%s)\n",mregnames[sp]);
+ push(4);
+ }
+ scratch_modified();
+ if(GAS){
+ emit(f,"\t.global\t__ieeeflt%c%c%c\n\tjbsr\t__ieeeflt%c%c%c\n\taddq.%s\t#4,%s\n",uns,xt,x_t[t&NQ],uns,xt,x_t[t&NQ],strshort[1],mregnames[sp]);
+ }else{
+ emit(f,"\tpublic\t__ieeeflt%c%c%c\n\tjsr\t__ieeeflt%c%c%c\n\taddq.%s\t#4,%s\n",uns,xt,x_t[t&NQ],uns,xt,x_t[t&NQ],strshort[1],mregnames[sp]);
+ }
+ pop(4);
+ restoreregsa(f,p);
+ if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)
+ stored0d1(f,&p->z,t);
+ else
+ move(f,0,d0,&p->z,0,t);
+ restoreregsd(f,p);
+ continue;
+ }
+ }
+ continue;
+ }
+ if((to&NQ)<(t&NQ)){
+ int zreg;
+ if(isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7){
+ zreg=p->z.reg;
+ }else{
+ zreg=get_reg(f,1,p,0);
+ }
+ if(sizetab[t&NQ]!=sizetab[LONG]||sizetab[to&NQ]!=sizetab[LONG]){
+ /* aufpassen, falls unsigned und Quelle==Ziel */
+ if((to&UNSIGNED)&&isreg(q1)&&zreg==p->q1.reg){
+ unsigned long l;
+ if((to&NQ)==CHAR) l=0xff; else l=0xffff;
+ emit(f,"\tand.%c\t#%lu,%s\n",cf?'l':x_t[t&NQ],l,mregnames[zreg]);
+ continue;
+ }
+ if((to&UNSIGNED)&&p->q1.am&&(zreg==p->q1.am->basereg||zreg==(p->q1.am->dreg&127))){
+ /* aufpassen, falls unsigned und Ziel im am */
+ unsigned long l;
+ if((to&NQ)==CHAR) l=0xff; else l=0xffff;
+ move(f,&p->q1,0,0,zreg,to);
+ emit(f,"\tand.%c\t#%lu,%s\n",cf?'l':x_t[t&NQ],l,mregnames[zreg]);
+ }else{
+ if(to&UNSIGNED)
+ emit(f,"\tmoveq\t#0,%s\n",mregnames[zreg]);
+ move(f,&p->q1,0,0,zreg,to);
+ }
+ if(!(to&UNSIGNED)){
+#ifdef M68K_16BIT_INT
+ if((to&NQ)==CHAR&&((t&NQ)==SHORT||(t&NQ)==INT)) emit(f,"\text.w\t%s\n",mregnames[zreg]);
+ if(((to&NQ)==SHORT||(to&NQ)==INT)&&msizetab[t&NQ]==4) emit(f,"\text.l\t%s\n",mregnames[zreg]);
+#else
+ if((to&NQ)==CHAR&&(t&NQ)==SHORT) emit(f,"\text.w\t%s\n",mregnames[zreg]);
+ if((to&NQ)==SHORT&&msizetab[t&NQ]==4) emit(f,"\text.l\t%s\n",mregnames[zreg]);
+#endif
+ if((to&NQ)==CHAR&&msizetab[t&NQ]==4){
+ if(cf||CPU>=68020)
+ emit(f,"\textb.l\t%s\n",mregnames[zreg]);
+ else
+ emit(f,"\text.w\t%s\n\text.l\t%s\n",mregnames[zreg],mregnames[zreg]);
+ }
+ }
+ }
+ if(!isreg(z)||p->z.reg!=zreg){
+ move(f,0,zreg,&p->z,0,t);
+ }
+ }else{
+ long diff;int m;
+ m=0;
+ if(p->q1.flags®){
+ p->q1.val.vmax=l2zm(0L);
+ p->q1.flags|=D16OFF;m=1;
+ }
+ diff=msizetab[to&NQ]-msizetab[t&NQ];
+ vmax=l2zm(diff);
+ p->q1.val.vmax=zmadd(p->q1.val.vmax,vmax);
+ move(f,&p->q1,0,&p->z,0,t);
+ vmax=l2zm(diff);
+ p->q1.val.vmax=zmsub(p->q1.val.vmax,vmax);
+ if(m) p->q1.flags&=~D16OFF;
+ if(compare_objects(&p->q1,&p->z))
+ cc_set=0;
+ }
+ continue;
+ }
+ if(ISFLOAT(t)&&FPU>68000) *fp='f'; else *fp=0;
+ if(c==MINUS||c==KOMPLEMENT){
+ int zreg;
+ if(ISFLOAT(t)){
+ if(FPU>68000){
+ if(isreg(z)) zreg=p->z.reg; else zreg=get_reg(f,2,p,1);
+ emit(f,"\tfneg.");
+ if(isreg(q1)) emit(f,"x\t%s",mregnames[p->q1.reg]);
+ else {emit(f,"%c\t",x_t[t&NQ]);emit_obj(f,&p->q1,t);}
+ emit(f,",%s\n",mregnames[zreg]);
+ if(!isreg(z)||p->z.reg!=zreg){
+ move(f,0,zreg,&p->z,0,t);
+ }
+ continue;
+ }else{
+ if(!OLD_SOFTFLOAT) ierror(0);
+ saveregs(f,p);
+ assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t);
+ scratch_modified();
+ if(GAS){
+ emit(f,"\t.global\t__ieeeneg%c\n\tjbsr\t__ieeeneg%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]);
+ }else{
+ emit(f,"\tpublic\t__ieeeneg%c\n\tjsr\t__ieeeneg%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]);
+ }
+ pop(msizetab[t&NQ]);
+ restoreregsa(f,p);
+ if((t&NQ)!=FLOAT)
+ stored0d1(f,&p->z,t);
+ else
+ move(f,0,d0,&p->z,0,t);
+ restoreregsd(f,p);
+ continue;
+ }
+ }
+ if(!cf&&compare_objects(&p->q1,&p->z)){
+ emit(f,"\t%s.%c\t",ename[c],x_t[t&NQ]);
+ emit_obj(f,&p->q1,t);emit(f,"\n");
+ continue;
+ }
+ if(isreg(z)&&p->z.reg>=d0/*&&p->z.reg<=d7*/)
+ zreg=p->z.reg; else zreg=get_reg(f,1,p,1);
+ if(!isreg(q1)||p->q1.reg!=zreg){
+ move(f,&p->q1,0,0,zreg,t);
+ }
+ emit(f,"\t%s.%c\t%s\n",ename[c],x_t[t&NQ],mregnames[zreg]);
+ if(!isreg(z)||p->z.reg!=zreg){
+ move(f,0,zreg,&p->z,0,t);
+ }
+ continue;
+ }
+ if(c==SETRETURN){
+ /* Returnwert setzen - q2.val.vmax==size, z.reg==Returnregister */
+ if(((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)&&p->z.reg==d0){
+ BSET(regs_modified,d0);BSET(regs_modified,10);
+ if(isconst(q1)){
+ unsigned char *ip=(unsigned char *)&p->q1.val.vdouble;
+ char *s;
+ if(GAS) s="0x"; else s="$";
+ emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,%s\n",s,ip[0],ip[1],ip[2],ip[3],mregnames[d0]);
+ emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,%s\n",s,ip[4],ip[5],ip[6],ip[7],mregnames[d1]);
+ continue;
+ }
+ if(isreg(q1)&&p->q1.reg>=fp0&&p->q1.reg<=fp7){
+ emit(f,"\tfmove.d\t%s,-(%s)\n\tmovem.l\t(%s)+,%s\n",mregnames[p->q1.reg],mregnames[sp],mregnames[sp],mregnames[d0d1]);
+ }else{
+ loadd0d1(f,&p->q1,t);
+ }
+ continue;
+ }
+ if((ISSTRUCT(t)||ISUNION(t))&&p->z.reg==d0){
+ long l=zm2l(p->q2.val.vmax);
+ emit(f,"\tmovem.l\t");emit_obj(f,&p->q1,t);
+ emit(f,",%s",mregnames[d0]);BSET(regs_modified,d0);
+ if(l>=8) {emit(f,"/%s",mregnames[d1]);BSET(regs_modified,d1);}
+ if(l>=12) {emit(f,"/%s",mregnames[a0]);BSET(regs_modified,a0);}
+ if(l>=16) {emit(f,"/%s",mregnames[a1]);BSET(regs_modified,a1);}
+ emit(f,"\n");
+ continue;
+ }
+ /* Wenn Returnwert ueber Zeiger gesetzt wird, nichts noetig */
+ if(p->z.reg){
+ move(f,&p->q1,0,0,p->z.reg,p->typf);
+ BSET(regs_modified,p->z.reg);
+ if(v->tattr&AMIINTERRUPT){
+ /* if necessary, set condition-codes */
+ if(p->z.reg!=d0) ierror(0);
+ if(isreg(q1)&&p->q1.reg==d0)
+ emit(f,"\ttst.%c\t%s\n",x_t[t&NQ],mregnames[d0]);
+ }
+ }
+ continue;
+ }
+ if(c==GETRETURN){
+ /* Returnwert holen - q2.val.vmax==size, q1.reg==Returnregister */
+ if(((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)&&(p->q1.reg==d0||p->q1.reg==d0d1)){
+ if(isreg(z)&&p->z.reg>=fp0&&p->z.reg<=fp7){
+ emit(f,"\tmovem.l\t%s,-(%s)\n\tfmove.d\t(%s)+,%s\n",mregnames[d0d1],mregnames[sp],mregnames[sp],mregnames[p->z.reg]);
+ }else{
+ stored0d1(f,&p->z,t);
+ }
+ continue;
+ }
+ if((ISSTRUCT(t)||ISUNION(t))&&p->q1.reg==d0){
+ long l=zm2l(p->q2.val.vmax);
+ emit(f,"\tmovem.l\t");
+ emit(f,"%s",mregnames[d0]);
+ if(l>=8) emit(f,"/%s",mregnames[d1]);
+ if(l>=12) emit(f,"/%s",mregnames[a0]);
+ if(l>=16) emit(f,"/%s",mregnames[a1]);
+ emit(f,",");emit_obj(f,&p->z,t);emit(f,"\n");
+ continue;
+ }
+
+ /* Wenn Returnwert ueber Zeiger gesetzt wird, nichts noetig */
+ cc_set=0;
+ if(p->q1.reg){
+ move(f,0,p->q1.reg,&p->z,0,p->typf);
+ if(!(p->z.flags®)||(p->z.reg!=p->q1.reg&&p->z.reg>=d0)){ cc_set=&p->z;cc_typ=p->typf;}
+ }
+ continue;
+ }
+ if(c==CALL){
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+ int sr=(USEFRAMEPOINTER||vlas)?fbp:sp;
+ long va_off=0;
+ if(USEFRAMEPOINTER||vlas){
+ emit(f,"\tmove.l\t%s,%s\n",mregnames[fbp],mregnames[d0]);
+ emit(f,"\tadd.l\t#%ld,%s\n",(long)(8+zm2l(va_offset(v)))+(PROFILER?16:0),mregnames[d0]);
+ }else{
+ emit(f,"\tmove.l\t%s,%s\n",mregnames[sp],mregnames[d0]);
+ emit(f,"\tadd.l\t#%s%d+%ld,%s\n",labprefix,offlabel,(long)(4+zm2l(va_offset(v)))+loff+(PROFILER?16:0),mregnames[d0]);
+ }
+ BSET(regs_modified,d0);
+ continue;
+ }
+ if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK))
+ callee_push(zum2ul(p->q1.v->fi->stack1));
+ else
+ stack_valid=0;
+ }else{
+ if((p->q1.flags&(REG|DREFOBJ))==DREFOBJ){
+ if(1/*CPU<68020*/){
+ emit(f,"\tpea\t%s%d(pc)\n",labprefix,++label);
+ emit(f,"\tmove.l\t");
+ }else
+ emit(f,"\t%s\t([",GAS?"jbsr":"jsr");
+ p->q1.flags&=~DREFOBJ;
+ emit_obj(f,&p->q1,POINTER);
+ p->q1.flags|=DREFOBJ;
+ if(1/*CPU<68020*/){
+ emit(f,",-(%s)\n",mregnames[sp]);
+ emit(f,"\trts\n");
+ emit(f,"%s%d%s\n",labprefix,label,GAS?":":"");
+ }else
+ emit(f,"])\n");
+ }else{
+ if(GAS){
+ emit(f,"\tjbsr\t");
+ }else{
+ emit(f,"\tjsr\t");
+ }
+ /* Wenn geta4() aufgerufen wurde, merken. */
+ if(use_sd&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p->q1.v->identifier,"geta4")&&p->q1.v->storage_class==EXTERN)
+ geta4=1;
+ if((p->q1.flags&(DREFOBJ|REG|KONST))==DREFOBJ) ierror(0);
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ push(4);
+ if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK))
+ callee_push(zum2ul(p->q1.v->fi->stack1));
+ else
+ stack_valid=0;
+ pop(4);
+ }
+ if(debug_info&&HUNKDEBUG) act_line=0;
+ if(!zmeqto(p->q2.val.vmax,l2zm(0L))){
+ notpopped+=zm2l(p->q2.val.vmax);
+ dontpop-=zm2l(p->q2.val.vmax);
+ if(!NODELAYEDPOP&&!(pushedreg&30)&&!vlas&&stackoffset==-notpopped){
+ /* Entfernen der Parameter verzoegern */
+ }else{
+ if(debug_info&&HUNKDEBUG&&!GAS){ act_line=p->line; emit(f,"\tdebug\t%d\n",act_line);}
+ emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[zm2l(p->q2.val.vmax)<=8],strshort[zm2l(p->q2.val.vmax)<32768],zm2l(p->q2.val.vmax),mregnames[sp]);
+ pop(zm2l(p->q2.val.vmax));
+ notpopped-=zm2l(p->q2.val.vmax);
+ }
+ }
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+ bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+ }else{
+ int i;
+ for(i=1;i<=MAXR;i++){
+ if(regscratch[i])
+ if(i<fp0||i>fp7||FPU>68000)
+ BSET(regs_modified,i);
+ }
+ }
+ continue;
+ }
+ if(c==TEST){
+ /* ConditionCodes schon gesetzt? */
+ cc_set=&p->q1;cc_typ=t;
+ comptyp=t;
+ if(cc_set_tst&&t==cc_typ_tst){
+ IC *branch;
+ if(t&UNSIGNED){
+ branch=p->next;
+ while(branch&&(branch->code<BEQ||branch->code>BGT))
+ branch=branch->next;
+ if(!branch) continue;
+ if(branch->code==BLE) branch->code=BEQ;
+ if(branch->code==BGT) branch->code=BNE;
+ if(branch->code==BGE) {branch->code=BRA;continue;}
+ if(branch->code==BLT) {branch->code=NOP;continue;}
+ }
+ if(compare_objects(&p->q1,cc_set_tst)&&p->q1.am==cc_set_tst->am&&zmeqto(p->q1.val.vmax,cc_set_tst->val.vmax)){
+ if(DEBUG&512){emit(f,"; tst eliminated: cc=");emit_obj(f,cc_set_tst,t);
+ emit(f,", q1=");emit_obj(f,&p->q1,t);emit(f,"\n");}
+ continue;
+ }
+ }
+ if(CPU<68020&&isreg(q1)&&p->q1.reg>=1&&p->q1.reg<=8){
+ /* tst ax gibt es nicht bei <68000 :-( */
+ if(regavailable(1)){
+ emit(f,"\tmove.%c\t%s,%s\n",x_t[t&NQ],mregnames[p->q1.reg],mregnames[get_reg(f,1,p,0)]);
+ }else{
+ emit(f,"\tcmp.%c\t#0,%s\n",cf?'l':'w',mregnames[p->q1.reg]);
+ }
+ continue;
+ }
+ if(ISFLOAT(t)&&FPU<=68000){
+ /* nicht sehr schoen */
+ int result=get_reg(f,1,p,0);
+ if(!OLD_SOFTFLOAT) ierror(0);
+ saveregs(f,p);
+ assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t);
+ scratch_modified();
+ if(GAS){
+ emit(f,"\t.global\t__ieeetst%c\n\tjbsr\t__ieeetst%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]);
+ }else{
+ emit(f,"\tpublic\t__ieeetst%c\n\tjsr\t__ieeetst%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]);
+ }
+ pop(msizetab[t&NQ]);
+ restoreregsa(f,p);
+ if(result!=d0) emit(f,"\tmove.l\t%s,%s\n",mregnames[d0],mregnames[result]);
+ emit(f,"\ttst.l\t%s\n",mregnames[result]);
+ restoreregsd(f,p);
+ continue;
+ }
+ if(isreg(q1)&&p->q1.reg>=fp0&&p->q1.reg<=fp7){
+ emit(f,"\tftst.x\t%s\n",mregnames[p->q1.reg]);
+ }else if(p->q1.flags&(VARADR|KONST)){
+ int r=get_reg(f,1,p,0);
+ emit(f,"\tmove.%c\t",x_t[t&NQ]);
+ emit_obj(f,&p->q1,t);
+ emit(f,",%s\n",mregnames[r]);
+ }else{
+ emit(f,"\t%stst.%c\t",fp,x_t[t&NQ]);emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(c==ASSIGN&&compare_objects(&p->q1,&p->z)) cc_set=0;
+ if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax);
+ assign(f,p,&p->q1,&p->z,c,zm2l(p->q2.val.vmax),t);
+ continue;
+ }
+ if(c==ADDRESS){
+ int zreg;
+ if(isreg(z)&&p->z.reg>=1&&p->z.reg<=8)
+ zreg=p->z.reg; else zreg=get_reg(f,0,p,0);
+ emit(f,"\tlea\t");emit_obj(f,&p->q1,t);
+ emit(f,",%s\n",mregnames[zreg]);
+ if(!isreg(z)||p->z.reg!=zreg){
+ move(f,0,zreg,&p->z,0,POINTER);
+ }
+ continue;
+ }
+ if(c==COMPARE){
+ int zreg;
+ comptyp=t;
+ if(isconst(q1)||isreg(q2)){
+ /* evtl. Argumente von cmp und nachfolgendes bcc umdrehen */
+ IC *n;obj m;
+ n=p->next;
+ while(n){
+ if(n->code>=BEQ&&n->code<BRA){
+ if(!p->z.flags){
+ if(DEBUG&1) printf("arguments of cmp exchanged\n");
+ m=p->q1;p->q1=p->q2;p->q2=m;
+ p->z.flags=1;
+ }
+ /* nachfolgenden Branch umdrehen */
+ switch(n->code){
+ case BGT: n->code=BLT;break;
+ case BLT: n->code=BGT;break;
+ case BGE: n->code=BLE;break;
+ case BLE: n->code=BGE;break;
+ }
+ break;
+ }
+ if(n->code==FREEREG) n=n->next; else break; /* compare ohne branch => leerer Block o.ae. */
+ }
+ }
+ if(ISFLOAT(t)){
+ if(FPU>68000){
+ if(isreg(q1)&&p->q1.reg>=fp0){
+ zreg=p->q1.reg;
+ }else{
+ zreg=get_reg(f,2,p,0);
+ move(f,&p->q1,0,0,zreg,t);
+ }
+ if(isreg(q2)){emit(f,"\tfcmp.x\t%s,%s\n",mregnames[p->q2.reg],mregnames[zreg]);continue;}
+ emit(f,"\tfcmp.%c\t",x_t[t&NQ]);emit_obj(f,&p->q2,t);
+ emit(f,",%s\n",mregnames[zreg]);
+ continue;
+ }else{
+ /* nicht sehr schoen */
+ int result=get_reg(f,1,p,0);
+ if(!OLD_SOFTFLOAT) ierror(0);
+ saveregs(f,p);
+ assign(f,p,&p->q2,0,PUSH,msizetab[t&NQ],t);
+ assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t);
+ scratch_modified();
+ if(GAS){
+ emit(f,"\t.global\t__ieeecmp%c\n\tjbsr\t__ieeecmp%c\n\tadd.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]);
+ }else{
+ emit(f,"\tpublic\t__ieeecmp%c\n\tjsr\t__ieeecmp%c\n\tadd.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]);
+ }
+ pop(2*msizetab[t&NQ]);
+ restoreregsa(f,p);
+ if(result!=d0) emit(f,"\tmove.l\t%s,%s\n",mregnames[d0],mregnames[result]);
+ emit(f,"\ttst.l\t%s\n",mregnames[result]);
+ restoreregsd(f,p);
+ continue;
+ }
+ }
+ if(cf&&x_t[t&NQ]!='l'){
+ if(isreg(q1)) zreg=p->q1.reg; else zreg=get_reg(f,1,p,0);
+ loadext(f,zreg,&p->q1,t);
+ if(isconst(q2)){
+ emit(f,"\tcmp.l\t");
+ emit_obj(f,&p->q2,t);
+ }else{
+ int r;
+ if(isreg(q2)) r=p->q2.reg; else r=get_reg(f,1,p,0);
+ loadext(f,r,&p->q2,t);
+ emit(f,"\tcmp.l\t%s",mregnames[r]);
+ }
+ emit(f,",%s\n",mregnames[zreg]);
+ continue;
+ }
+ if((p->q2.flags&(KONST|VARADR))&&!(p->q1.flags&(KONST|VARADR))&&(!cf||isreg(q1))){
+ emit(f,"\tcmp.%c\t",x_t[t&NQ]);emit_obj(f,&p->q2,t);
+ emit(f,",");emit_obj(f,&p->q1,t);emit(f,"\n");
+ continue;
+ }
+ if(isreg(q1)){
+ zreg=p->q1.reg;
+ }else{
+ zreg=get_reg(f,1,p,1); /* hier evtl. auch Adressregister nehmen */
+ move(f,&p->q1,0,0,zreg,t);
+ }
+ emit(f,"\tcmp.%c\t",x_t[t&NQ]);emit_obj(f,&p->q2,t);
+ emit(f,",%s\n",mregnames[zreg]);
+ continue;
+ }
+ if(c==ADDI2P||c==SUBIFP){
+ int zreg=-1,r;
+
+ /* hier die zweite Alternative mit isreg() schreiben? */
+ if((((p->q2.flags®)&&(p->z.flags®)&&p->q2.reg==p->z.reg&&(!(p->q1.flags®)||p->q1.reg!=p->z.reg))||
+ (compare_objects(&p->q2,&p->z)&&!compare_objects(&p->q1,&p->z)))){
+ obj m;
+ if(c==ADDI2P&&x_t[t&NQ]=='l'){
+ m=p->q1;p->q1=p->q2;p->q2=m;
+ }else{
+ if(!cf&&x_t[t&NQ]=='l'&&isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7){
+ m=p->q1;p->q1=p->q2;p->q2=m;
+ c=ADDI2P;
+ emit(f,"\tneg.%c\t",x_t[t&NQ]);
+ emit_obj(f,&p->q1,t);emit(f,"\n");
+ }else{
+ zreg=get_reg(f,0,p,0);
+ }
+ }
+ }
+
+ if(isreg(q1)&&p->q1.reg<=8&&isreg(z)&&p->z.reg<=8&&p->q1.reg!=p->z.reg){
+ /* q1 und z Adressregister => lea nehmen */
+ if(isconst(q2)){
+ eval_const(&p->q2.val,t);
+ if(c==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+ if(CPU>=68020||(zmleq(vmax,l2zm(32767))&&zmleq(l2zm(-32768),vmax))){
+ emit(f,"\tlea\t(%ld",zm2l(vmax));
+ if(!GAS&&zm2l(vmax)>0x7fff)
+ emit(f,".l");
+ emit(f,",%s),%s\n",mregnames[p->q1.reg],mregnames[p->z.reg]);
+ continue;
+ }
+ }else if(c==ADDI2P&&isreg(q2)){
+ emit(f,"\tlea\t(%s,%s.%c),%s\n",mregnames[p->q1.reg],mregnames[p->q2.reg],x_t[t&NQ],mregnames[p->z.reg]);
+ continue;
+ }
+ }
+ if(compare_objects(&p->q1,&p->z)){
+ if(isconst(q2)&&(!cf||isquickkonst2(&p->q2.val,t))){
+ if(c==ADDI2P)
+ emit(f,"\tadd%s.l\t",quick[isquickkonst2(&p->q2.val,t)]);
+ else
+ emit(f,"\tsub%s.l\t",quick[isquickkonst2(&p->q2.val,t)]);
+ emit_obj(f,&p->q2,t);emit(f,",");
+ emit_obj(f,&p->z,POINTER);emit(f,"\n");
+ continue;
+ }
+ if(isreg(q1)&&(x_t[t&NQ]=='l'||p->q1.reg<=8)){
+ if(c==ADDI2P)
+ emit(f,"\tadd.%c\t",x_t[t&NQ]);
+ else
+ emit(f,"\tsub.%c\t",x_t[t&NQ]);
+ emit_obj(f,&p->q2,t);emit(f,",%s\n",mregnames[p->z.reg]);
+ continue;
+ }
+ if(isreg(q2)&&p->q2.reg>=9&&p->q2.reg<=16){
+ r=p->q2.reg;
+ }else{
+ r=get_reg(f,1,p,0);
+ move(f,&p->q2,0,0,r,t);
+ }
+ if(x_t[t&NQ]!='l'&&(!isreg(z)||p->z.reg<1||p->z.reg>8)){
+ /* wenn Ziel kein Adressregister, muss short erst auf long */
+ /* char darf hier nicht auftreteten und long passt schon */
+ if(t&UNSIGNED){
+ if(CPU>=68040)
+ emit(f,"\tand.l\t#65535,%s\n",mregnames[r]);
+ else
+ emit(f,"\tswap\t%s\n\tclr.w\t%s\n\tswap\t%s\n",mregnames[r],mregnames[r],mregnames[r]);
+ }else
+ emit(f,"\text.l\t%s\n",mregnames[r]);
+ t=POINTER;
+ }
+ /* if(c==ADDI2P)
+ emit(f,"\tadd.%c\t%s,",x_t[t&NQ],mregnames[r]);
+ else
+ emit(f,"\tsub.%c\t%s,",x_t[t&NQ],mregnames[r]);
+ emit_obj(f,&p->z,t);emit(f,"\n");*/
+ if(c==ADDI2P)
+ add(f,0,r,&p->z,0,t);
+ else
+ sub(f,0,r,&p->z,0,t);
+ continue;
+ }
+ if(isreg(z)&&zreg==-1&&p->z.reg>=1&&p->z.reg<=d7)
+ zreg=p->z.reg;
+ else
+ zreg=get_reg(f,0,p,0);
+ /* Spezialfall, falls Ziel Datenregister und short */
+ /* nicht schoen, aber auf die Schnelle... */
+ if(x_t[t&NQ]!='l'&&zreg>8){
+ move(f,&p->q2,0,0,zreg,t);
+ if(t&UNSIGNED){
+ if(CPU>=68040)
+ emit(f,"\tand.l\t#65535,%s\n",mregnames[zreg]);
+ else
+ emit(f,"\tswap\t%s\n\tclr.w\t%s\n\tswap\t%s\n",mregnames[zreg],mregnames[zreg],mregnames[zreg]);
+ }else
+ emit(f,"\text.l\t%s\n",mregnames[zreg]);
+ if(c==SUBIFP) emit(f,"\tneg.l\t%s\n",mregnames[zreg]);
+ add(f,&p->q1,0,0,zreg,POINTER);
+ if(!isreg(z)||p->z.reg!=zreg)
+ move(f,0,zreg,&p->z,0,POINTER);
+ continue;
+ }
+ if(!isreg(q1)||p->q1.reg!=zreg){
+ move(f,&p->q1,0,0,zreg,POINTER);
+ }
+ if(c==ADDI2P)
+ add(f,&p->q2,0,0,zreg,t);
+ else
+ sub(f,&p->q2,0,0,zreg,t);
+ if(!isreg(z)||p->z.reg!=zreg){
+ move(f,0,zreg,&p->z,0,POINTER);
+ }
+ continue;
+ }
+ if((c>=OR&&c<=AND)||c==MULT||c==ADD){
+ if(!isreg(q1)&&!isreg(z)&&isreg(q2)){
+ obj o;
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ }
+ }
+ switch_IC(p);
+ if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)){
+ int zreg,q1reg,q2reg;
+ if(isconst(q2)&&
+ (!(p->q1.flags®)||!(p->z.flags®)||p->q1.reg!=p->z.reg)&&
+ (!(p->q1.flags&VAR)||!(p->z.flags&VAR)||p->q1.v!=p->z.v)&&
+ ((c>=OR&&c<=AND)||c==ADD||c==MULT)){
+ obj o;
+ if(c==MULT){
+ eval_const(&p->q2.val,t);
+ if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)&&!pof2(vumax)){
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ }
+ }else{
+ if(!cf||!ISHWORD(t)){
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ }
+ }
+ }
+ if(ISFLOAT(t)){
+ if(FPU>68000){
+ if(compare_objects(&p->q2,&p->z)&&!compare_objects(&p->q2,&p->q1)){
+ obj m;
+ if(c==ADD||c==MULT){
+ m=p->q1;p->q1=p->q2;p->q2=m;
+ }else{
+ if(isreg(q2)){
+ if(c==SUB){
+ emit(f,"\tfneg.x\t%s\n",mregnames[p->q2.reg]);
+ m=p->q1;p->q1=p->q2;p->q2=m;
+ p->code=c=ADD;
+ }else{
+ int tmp=get_reg(f,2,p,0);
+ move(f,&p->q2,0,0,tmp,t);
+ p->q2.reg=tmp;
+ p->q2.flags=REG;
+ }
+ }
+ }
+ }
+ if(isreg(z)&&p->z.reg>=fp0)
+ zreg=p->z.reg;
+ else
+ zreg=get_reg(f,2,p,1);
+ if(!isreg(q1)||p->q1.reg!=p->z.reg)
+ move(f,&p->q1,0,0,zreg,t);
+ emit(f,"\tf%s.",ename[c]);
+ if(isreg(q2))
+ emit(f,"x\t");
+ else
+ emit(f,"%c\t",x_t[t&NQ]);
+ emit_obj(f,&p->q2,t);
+ emit(f,",%s\n",mregnames[zreg]);
+ if(!isreg(z)||p->z.reg!=zreg){
+ move(f,0,zreg,&p->z,0,t);
+ }
+ continue;
+ }else{
+ if(!OLD_SOFTFLOAT) ierror(0);
+ saveregs(f,p);
+ assign(f,p,&p->q2,0,PUSH,msizetab[t&NQ],t);
+ assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t);
+ scratch_modified();
+ if(GAS){
+ emit(f,"\t.global\t__ieee%s%c\n\tjbsr\t__ieee%s%c\n\tadd.%s\t#%ld,%s\n",ename[c],x_t[t&NQ],ename[c],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]);
+ }else{
+ emit(f,"\tpublic\t__ieee%s%c\n\tjsr\t__ieee%s%c\n\tadd.%s\t#%ld,%s\n",ename[c],x_t[t&NQ],ename[c],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]);
+ }
+ pop(2*msizetab[t&NQ]);
+ restoreregsa(f,p);
+ if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)
+ stored0d1(f,&p->z,t);
+ else
+ move(f,0,d0,&p->z,0,t);
+ restoreregsd(f,p);
+ continue;
+ }
+ }
+ if(((c==MULT||c==DIV)||(c==MOD&&(p->typf&UNSIGNED)))&&isconst(q2)){
+ /* ersetzt mul etc. mit Zweierpotenzen */
+ /* hier evtl. noch Fehler */
+ long ln;
+ eval_const(&p->q2.val,t);
+ if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+ if(ln=pof2(vumax)){
+ if(c==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ p->code=AND;
+ }else{
+ vmax=l2zm(ln-1);
+ if(c==DIV){
+ p->code=RSHIFT;
+ shiftisdiv=1;
+ }else
+ p->code=LSHIFT;
+ }
+ c=p->code;
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ if(c==AND){
+ insert_const(&p->q2.val,t);
+ }else{
+ insert_const(&p->q2.val,INT);
+ p->typf2=INT;
+ }
+ }
+ }
+ }
+ if(c==DIV||c==MOD){
+ if(x_t[t&NQ]=='l'&&CPU<68020){
+ /* das hier ist auch nicht allzu schoen */
+ char *fname;
+ cc_set=0; /* Library-Funktionen setzen cc nicht immer */
+ saveregs(f,p);
+ emit(f,"\tmove.l\t"); emit_obj(f,&p->q2,t);
+ emit(f,",-(%s)\n",mregnames[sp]);
+ push(4);
+ emit(f,"\tmove.l\t"); emit_obj(f,&p->q1,t);
+ emit(f,",-(%s)\n",mregnames[sp]);
+ push(4);
+ if(t&UNSIGNED) fname="divu"; else fname="divs";
+ scratch_modified();
+ if(GAS){
+ emit(f,"\t.global\t__l%s\n\tjbsr\t__l%s\n",fname,fname);
+ }else{
+ emit(f,"\tpublic\t__l%s\n\tjsr\t__l%s\n",fname,fname);
+ }
+ emit(f,"\taddq.%s\t#8,%s\n",strshort[1],mregnames[sp]);
+ if(c==MOD) emit(f,"\tmove.l\td1,d0\n");
+ pop(8);
+ restoreregsa(f,p);
+ move(f,0,d0,&p->z,0,t);
+ restoreregsd(f,p);
+ continue;
+ }
+
+ }
+ /* hier die zweite Alternative mit isreg() schreiben? */
+ if(compare_objects(&p->q2,&p->z)&&!compare_objects(&p->q2,&p->q1)){
+ obj m;
+ if((c>=OR&&c<=AND)||c==ADD||c==SUB){
+ if(c!=SUB){
+ m=p->q1;p->q1=p->q2;p->q2=m;
+ }else{
+ if(isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7){
+ m=p->q1;p->q1=p->q2;p->q2=m;
+ c=ADD;
+ emit(f,"\tneg.%c\t",x_t[t&NQ]);
+ emit_obj(f,&p->q1,t);emit(f,"\n");
+ }
+ }
+ }
+ }
+ if(compare_objects(&p->q1,&p->z)){
+ if((c>=OR&&c<=AND)||c==ADD||c==SUB){
+ int r;
+ if(isconst(q2)&&(!cf||isreg(z)||((c==ADD||c==SUB)&&isquickkonst2(&p->q2.val,t&NQ)))){
+ if(cf&&((t&NQ)==CHAR||ISHWORD(t))){
+ if(isreg(q1)) r=p->q1.reg; else r=get_reg(f,1,p,1);
+ loadext(f,r,&p->q1,t);
+ emit(f,"\t%s.l\t",ename[c]);
+ emit_obj(f,&p->q2,t);
+ emit(f,",%s\n",mregnames[r]);
+ move(f,0,r,&p->z,0,t);
+ continue;
+ }else{
+ if(c==ADD) {add(f,&p->q2,0,&p->z,0,t);continue;}
+ if(c==SUB) {sub(f,&p->q2,0,&p->z,0,t);continue;}
+ emit(f,"\t%s.%c\t",ename[c],x_t[t&NQ]);
+ emit_obj(f,&p->q2,t);emit(f,",");
+ emit_obj(f,&p->z,t);emit(f,"\n");
+ }
+ continue;
+ }
+ if(!isreg(z)&&(!cf||x_t[t&NQ]=='l')){
+ if(isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7)
+ r=p->q2.reg; else r=get_reg(f,1,p,0);
+ if(!isreg(q2)||p->q2.reg!=r){
+ move(f,&p->q2,0,0,r,t);
+ }
+ emit(f,"\t%s.%c\t%s,",ename[c],x_t[t&NQ],mregnames[r]);
+ emit_obj(f,&p->z,t);emit(f,"\n");
+ continue;
+ }
+ }
+ }
+ /* bei xor oder asl (ausser 0<=const<=8) muss q2 in Register */
+ if(isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7){
+ q2reg=p->q2.reg;
+ }else{
+ if(c==LSHIFT||c==RSHIFT||c==XOR){
+ int t2=q2typ(p)&NU;
+ eval_const(&p->q2.val,t2);
+ if(c==XOR||!isconst(q2)||!isquickkonst2(&p->q2.val,t2)){
+ if((c==LSHIFT||c==RSHIFT)&&(p->typf2&NQ)==LLONG){
+ if(!isreg(q2)){
+ q2reg=get_reg(f,1,p,0);
+ emit(f,"\tmove.l\t");
+ emit_lword(f,&p->q2);
+ emit(f,",%s\n",mregnames[q2reg]);
+ }else{
+ if(!reg_pair(p->q2.reg,&rp)) ierror(0);
+ q2reg=rp.r2;
+ }
+ }else{
+ q2reg=get_reg(f,1,p,0);
+ move(f,&p->q2,0,0,q2reg,t2);
+ }
+ }else q2reg=0;
+ }else{
+ q2reg=0;
+ }
+ }
+ if(c==MOD&&!ISHWORD(t)){
+ int modreg;
+ if(isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&p->z.reg!=q2reg)
+ zreg=p->z.reg; else zreg=get_reg(f,1,p,0);
+ modreg=get_reg(f,1,p,1);
+ if(modreg==zreg) modreg=get_reg(f,1,p,0);
+ move(f,&p->q1,0,0,modreg,t);
+ if(0 /*CPU==68060*/){
+ /* div?l.l wird da emuliert? */
+ emit(f,"\tsmi\t%s\n\textb.l\t%s\n",mregnames[zreg],mregnames[zreg]);
+ if(t&UNSIGNED) emit(f,"\tdivu.%c\t",x_t[t&NQ]); else emit(f,"\tdivs.%c\t",x_t[t&NQ]);
+ }else{
+ if(t&UNSIGNED) emit(f,"\tdivul.%c\t",x_t[t&NQ]); else emit(f,"\tdivsl.%c\t",x_t[t&NQ]);
+ }
+ emit_obj(f,&p->q2,t);
+ emit(f,",%s:%s\n",mregnames[zreg],mregnames[modreg]);
+ move(f,0,zreg,&p->z,0,t);
+ cc_set=0;
+ continue;
+ }
+ if(isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&(p->z.reg!=q2reg||(isreg(q1)&&p->q1.reg==q2reg)))
+ zreg=p->z.reg; else zreg=get_reg(f,1,p,1);
+ if(isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7)
+ q1reg=p->q1.reg; else q1reg=0;
+ if(q1reg!=zreg){
+ move(f,&p->q1,0,0,zreg,t);
+ }
+ if(c!=MULT&&c!=DIV&&c!=MOD&&c!=ADD&&c!=SUB){
+ if(cf&&c==RSHIFT){
+ if(cf&&(t&NU)==CHAR)
+ emit(f,"\textb.l\t%s\n",mregnames[zreg]);
+ else if(cf&&(t&NU)==SHORT)
+ emit(f,"\text.w\t%s\n",mregnames[zreg]);
+ if(cf&&(t&NU)==(UNSIGNED|CHAR))
+ emit(f,"\tand.l\t#255,%s\n",mregnames[zreg]);
+ else if(cf&&(t&NU)==(UNSIGNED|SHORT))
+ emit(f,"\tand.l\t#65535,%s\n",mregnames[zreg]);
+ }
+ if(shiftisdiv&&!(t&UNSIGNED)){
+ unsigned long l;
+ eval_const(&p->q2.val,p->typf2);
+ l=(1<<zum2ul(vumax))-1;
+ if(isreg(q1)&&p->q1.reg==zreg)
+ emit(f,"\ttst.%c\t%s\n",x_t[t&NQ],mregnames[zreg]);
+ emit(f,"\tbge\t%s%d\n",labprefix,++label);
+ emit(f,"\tadd%s.%c\t#%ld,%s\n",(l<=7?"q":""),x_t[t&NQ],l,mregnames[zreg]);
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ if(c==RSHIFT&&!(t&UNSIGNED))
+ emit(f,"\tasr.%c\t",cf?'l':x_t[t&NQ]);
+ else
+ emit(f,"\t%s.%c\t",ename[c],cf?'l':x_t[t&NQ]);
+ if(q2reg)
+ emit(f,"%s",mregnames[q2reg]);
+ else
+ emit_obj(f,&p->q2,q2typ(p));
+ emit(f,",%s\n",mregnames[zreg]);
+ }else{
+ if(c==ADD) add(f,&p->q2,q2reg,0,zreg,t);
+ if(c==SUB) sub(f,&p->q2,q2reg,0,zreg,t);
+ if(c==MULT||c==DIV||c==MOD) mult(f,&p->q2,q2reg,0,zreg,t,c,p);
+ }
+ if((!isreg(z)||p->z.reg!=zreg)){
+ move(f,0,zreg,&p->z,0,t);
+ }
+ continue;
+ }
+ ierror(0);
+ }
+ if(notpopped){
+ emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[notpopped<=8],strshort[notpopped<32768],notpopped,mregnames[sp]);
+ pop(notpopped);notpopped=0;
+ }
+ function_bottom(f,v,zm2l(offset));
+ if(debug_info&&!HUNKDEBUG){
+ emit(f,"%s%d:\n",labprefix,++label);
+ dwarf2_function(f,v,label);
+ if(f) section=-1;
+ }
+ pushflag=0;
+}
+
+/*FIXME*/
+int shortcut(int code,int typ)
+{
+ if(!cf&&(code==COMPARE||code==ADD||code==SUB||code==AND||code==OR||code==XOR||code==LSHIFT||code==RSHIFT)) return(1);
+ if(!cf&&code==MULT&&(typ&NQ)!=CHAR) return 1;
+
+ return 0;
+}
+void init_db(FILE *f)
+{
+ if(!HUNKDEBUG){
+ if(GAS)
+ dwarf2_setup(sizetab[POINTER],".byte",".2byte",".4byte",".4byte","l","_",".section");
+ else
+ dwarf2_setup(sizetab[POINTER],"dc.b","dc.w","dc.l","dc.l","l","_","section");
+ dwarf2_print_comp_unit_header(f);
+ }
+}
+void cleanup_db(FILE *f)
+{
+ if(!HUNKDEBUG&&f){
+ dwarf2_cleanup(f);
+ if(f) section=-1;
+ }
+}
+void cleanup_cg(FILE *f)
+{
+ title(f);
+ if(f&&stack_check){
+ if(GAS)
+ emit(f,"\t.global\t___stack_check\n");
+ else
+ emit(f,"\tpublic\t___stack_check\n");
+ }
+ /*printf("pushed %d, saved %d, removed allocreg %d\n",missing,savedemit,savedalloc);*/
+ return;
+}
+
+/* mark instructions which can (probably) be implemented with faster
+ machine-code than the IC migh suggest, e.g. an addition which can
+ be merged with a load bz use of target addressing-modes;
+ the optimizer should hesitate to modifz such instructions if it's not
+ a definite win */
+
+static int is_single_eff_ic(IC *p)
+{
+ Var *v;
+ if(p->code!=ADDI2P&&p->code!=SUBIFP)
+ return 0;
+ if(!isconst(q2)){
+ if(CONSERVATIVE_SR){
+ if((p->q2.flags&(VAR|DREFOBJ))!=VAR)
+ return 0;
+ if(p->q2.v->storage_class==STATIC||p->q2.v->storage_class==EXTERN)
+ return 0;
+ }else
+ return 0;
+ }
+ if((p->q1.flags&(VAR|DREFOBJ))!=VAR)
+ return 0;
+ if(p->q1.v->storage_class==STATIC||p->q1.v->storage_class==EXTERN)
+ return 0;
+ if((p->z.flags&(VAR|DREFOBJ))!=VAR)
+ return 0;
+ if(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)
+ return 0;
+ v=p->z.v;
+ for(p=p->next;p;p=p->next){
+ int c=p->code;
+ if(c==LABEL||(c>=BEQ&&c<=BRA))
+ return 0;
+ if((p->q1.flags&VAR)&&p->q1.v==v){
+ if(p->q1.flags&DREFOBJ)
+ return 1;
+ else
+ return 0;
+ }
+ if((p->q2.flags&VAR)&&p->q2.v==v){
+ if(p->q2.flags&DREFOBJ)
+ return 1;
+ else
+ return 0;
+ }
+ if((p->z.flags&VAR)&&p->z.v==v){
+ if(p->z.flags&DREFOBJ)
+ return 1;
+ else
+ return 0;
+ }
+ }
+}
+void mark_eff_ics(void)
+{
+ IC *p;
+ for(p=first_ic;p;p=p->next){
+ if(is_single_eff_ic(p))
+ p->flags|=EFF_IC;
+ else
+ p->flags&=~EFF_IC;
+ }
+}
+
+int reg_pair(int r,rpair *p)
+ /* Returns 0 if the register is no register pair. If r */
+ /* is a register pair non-zero will be returned and the */
+ /* structure pointed to p will be filled with the two */
+ /* elements. */
+{
+ if(r<=fp7) return 0;
+ if(p){
+ switch(r){
+ case d0d1: p->r1=d0;p->r2=d1;break;
+ case d2d3: p->r1=d2;p->r2=d3;break;
+ case d4d5: p->r1=d4;p->r2=d5;break;
+ case d6d7: p->r1=d6;p->r2=d7;break;
+ default: ierror(0);
+ }
+ }
+ return 1;
+}
+
+int emit_peephole(void)
+{
+ int entries,i,r1,r2,r3,r4;
+ char *asmline[EMIT_BUF_DEPTH],c1,c2,c3,c4,e;
+
+ if(OLDPEEPHOLE) return 0;
+ i=emit_l;
+ if(emit_f==0)
+ entries=i-emit_f+1;
+ else
+ entries=EMIT_BUF_DEPTH;
+ asmline[0]=emit_buffer[i];
+ if(entries>=2){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[1]=emit_buffer[i];
+ if(sscanf(asmline[1],"\tmove.l\t(a7)+,%c%d\n%c",&c1,&r1,&e)==2&&
+ sscanf(asmline[0],"\tmove.l\t%c%d,-(a7%c",&c2,&r2,&e)==3&&
+ c1==c2&&r1==r2&&(c1=='a'||c1=='d')&&r1>=0&&r1<=7&&e==')'){
+ sprintf(asmline[1],"\tmove.l\t(a7),%c%d\n",c1,r1);
+ remove_asm();
+ savedemit++;
+ return 1;
+ }
+ if(sscanf(asmline[1],"\tmovem.l\t(a7)+,%c%d\n%c",&c1,&r1,&e)==2&&
+ sscanf(asmline[0],"\tmove.l\t%c%d,-(a7%c",&c2,&r2,&e)==3&&
+ c1==c2&&r1==r2&&(c1=='a'||c1=='d')&&r1>=0&&r1<=7&&e==')'){
+ sprintf(asmline[1],"\tmove.l\t(a7),%c%d\n",c1,r1);
+ remove_asm();
+ savedemit++;
+ return 1;
+ }
+
+ if(sscanf(asmline[1],"\tmove.l\t%c%d,%c%d\n%c",&c1,&r1,&c2,&r2,&e)==4&&
+ sscanf(asmline[0],"\tmove.l\t%c%d,%c%d\n%c",&c3,&r3,&c4,&r4,&e)==4&&
+ c1==c4&&r1==r4&&c2==c3&&r2==r3&&r1>=0&&r1<=7&&r2>=0&&r2<=7&&
+ (c1=='a'||c1=='d')&&(c2=='a'||c2=='d')){
+ /* create tst instruction if condition codes of address register are needed */
+ if(c1=='d'&&c2=='a'&&cc_set!=0&&(cc_set->flags&(REG|DREFOBJ))==REG&&cc_set->reg==a0+r2)
+ sprintf(asmline[0],"\ttst.l\t%s\n",mregnames[d0+r1]);
+ else
+ remove_asm();
+ savedemit++;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+char *use_libcall(int c,int t,int t2)
+{
+ static char fname[32];
+ char *ret=0;
+ int f;
+
+ t&=NU;
+ t2&=NU;
+
+ if(c==LSHIFT&&((t&NQ)==LLONG)) return "_lshint64";
+ if(c==RSHIFT&&t==LLONG) return "_rshsint64";
+ if(c==RSHIFT&&t==(UNSIGNED|LLONG)) return "_rshuint64";
+
+
+ if(FPU>68000){
+ if(c!=CONVERT) return 0;
+ if((!ISFLOAT(t)||(t2&NQ)!=LLONG)&&
+ (!ISFLOAT(t2)||(t&NQ)!=LLONG))
+ return 0;
+ }
+ if(OLD_SOFTFLOAT) return 0;
+
+ if(t==LDOUBLE) t=DOUBLE;
+ if(t2==LDOUBLE) t2=DOUBLE;
+ if(FLOAT64){
+ if(t==FLOAT) t=DOUBLE;
+ if(t2==FLOAT) t2=DOUBLE;
+ }
+
+ if(c==COMPARE){
+ if(ISFLOAT(t)){
+ sprintf(fname,"_ieeecmp%c",x_t[t]);
+ ret=fname;
+ }
+ }else if(c==CONVERT){
+ if(t2==INT) t2=(zm2l(sizetab[INT])==4?LONG:SHORT);
+ if(t2==(UNSIGNED|INT)) t2=(sizetab[INT]==4?(UNSIGNED|LONG):(UNSIGNED|SHORT));
+ if(t==FLOAT&&t2==DOUBLE) return "_ieeed2s";
+ if(t==DOUBLE&&t2==FLOAT) return "_ieees2d";
+ if(t==DOUBLE&&t2==DOUBLE) return 0;
+ if(t==FLOAT||t==DOUBLE){
+ if((t2&NQ)==LLONG)
+ sprintf(fname,"_%cint64toflt%s",(t2&UNSIGNED)?'u':'s',t==FLOAT?"32":"64");
+ else
+ sprintf(fname,"_ieeeflt%c%c",(t2&UNSIGNED)?'u':'s',x_t[t]);
+ ret=fname;
+ }
+ if(t2==FLOAT||t2==DOUBLE){
+ if((t&NQ)==LLONG)
+ sprintf(fname,"_flt%sto%cint64",t2==FLOAT?"32":"64",(t&UNSIGNED)?'u':'s');
+ else
+ sprintf(fname,"_ieeefix%c%c%c",x_t[t2],(t2&UNSIGNED)?'u':'s',x_t[t&NQ]);
+ ret=fname;
+ }
+ }else if(ISFLOAT(t)){
+ if(c==MINUS){
+ sprintf(fname,"_ieeeneg%c",x_t[t&NQ]);
+ ret=fname;
+ }else if(c>=ADD&&c<=DIV){
+ sprintf(fname,"_ieee%s%c",ename[c],x_t[t&NQ]);
+ ret=fname;
+ }
+ if(c==TEST){
+ sprintf(fname,"_ieeetst%c",x_t[t&NQ]);
+ ret=fname;
+ }
+ }else if(CPU<68020&&!OLDLIBCALLS){
+ if((c==DIV||c==MOD)&&ISINT(t)&&zm2l(sizetab[t&NQ])==4){
+ sprintf(fname,"_%s%c",ename[c],(t&UNSIGNED)?'u':'s');
+ ret=fname;
+ }
+ }
+ return ret;
+}
+
+
+int reg_parm(treg_handle *p,type *t,int mode,type *fkt)
+{
+ int f;
+
+ if(!fkt||fkt->flags!=FUNKT)
+ ierror(0);
+
+ if(!fkt->next)
+ ierror(0);
+
+ if(stdargs(fkt))
+ return 0;
+
+ f=t->flags&NQ;
+ if(mode/*||f==LLONG||!ISSCALAR(f)*/)
+ return 0;
+ if(ISPOINTER(f)){
+ if(p->ar>ascratch)
+ return 0;
+ else
+ return a0+p->ar++;
+ }
+ if(ISFLOAT(f)||f==LLONG){
+ if(FPU<=68000||f==LLONG){
+ if(rparmtype==PARMSAS) return 0;
+ if(f!=FLOAT){
+ if(p->dr!=0) return 0;
+ p->dr+=2;
+ return d0d1;
+ }
+ if(p->dr>dscratch)
+ return 0;
+ else
+ return d0+p->dr++;
+ }else{
+ if(p->fr>fscratch)
+ return 0;
+ else
+ return fp0+p->fr++;
+ }
+ }
+ if(!ISINT(f)) return 0;
+ if(p->dr>dscratch)
+ return 0;
+ else
+ return d0+p->dr++;
+}
+
+int handle_pragma(const char *s)
+{
+ if(!strncmp("stdargs-on",s,10)){
+ add_stdargs=1;
+ return 1;
+ }
+ if(!strncmp("stdargs-off",s,11)){
+ add_stdargs=0;
+ return 1;
+ }
+ return 0;
+}
+
+void add_var_hook_pre(const char *identifier, type *t, int storage_class,const_list *clist)
+{
+ if(!add_stdargs) return;
+ if(ISFUNC(t->flags))
+ add_attr(&t->next->attr,"__stdargs");
+}
diff --git a/machines/m68k/machine.dt b/machines/m68k/machine.dt
new file mode 100755
index 0000000..526c8d4
--- /dev/null
+++ b/machines/m68k/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/m68k/machine.h b/machines/m68k/machine.h
new file mode 100644
index 0000000..c9d2afe
--- /dev/null
+++ b/machines/m68k/machine.h
@@ -0,0 +1,118 @@
+/* $VER: vbcc (m68k/machine.h) $Revision: 1.13 $ */
+
+#include "dt.h"
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+typedef struct AddressingMode{
+ int basereg;
+ long dist;
+ int skal;
+ int dreg;
+} AddressingMode;
+
+/* The number of registers of the target machine. */
+#define MAXR 28
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 35
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+extern int MINADDI2P;
+
+/* This specifies the smallest unsigned type that can be added to a */
+/* pointer. */
+#define MINADDUI2P (UNSIGNED|INT)
+
+
+/* This specifies the biggest integer type that can be added to a */
+/* pointer. */
+#define MAXADDI2P LONG
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 1
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 0
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 1
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 256
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES 1
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 2
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/* We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/* we have a mark_eff_ics function */
+#define HAVE_TARGET_EFF_IC 1
+
+/* we have register-pairs */
+#define HAVE_REGPAIRS 1
+
+#define HAVE_REGPARMS 1
+
+struct reg_handle {
+ int dr,ar,fr;
+};
+
+
+#define JUMP_TABLE_DENSITY 0.8
+#define JUMP_TABLE_LENGTH 8
+
+/* support for variable-length arrays */
+#define ALLOCVLA_REG 9
+#define ALLOCVLA_INLINEASM "\taddq.l\t#3,d0\n\tand.b\t#252,d0\n\tsub.l\td0,a7\n\tmove.l\ta7,d0"
+#define FREEVLA_REG 0
+/* TODO: find a better solution some time */
+#define FREEVLA_INLINEASM "\tmove.l\t(a7),a7\n\tsubq.l\t#4,a7"
+#define OLDSPVLA_INLINEASM "\tmove.l\ta7,d0"
+#define FPVLA_REG 6
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/* We have a target-specific add_var hook */
+#define HAVE_TARGET_VARHOOK_PRE
+
+#define HAVE_POF2OPT 1
+
+#ifndef M68K_16BIT_INT
+#define HAVE_INT_SIZET 1
+#endif
diff --git a/machines/m68ks/machine.c b/machines/m68ks/machine.c
new file mode 100755
index 0000000..ca342b5
--- /dev/null
+++ b/machines/m68ks/machine.c
@@ -0,0 +1,7 @@
+/* Code generator for Motorola 680x0 CPUs. Supports 68000-68060+68881/2 */
+/* and ColdFire. */
+/* PhxAss and the GNU assembler is supported. */
+
+/* stub for ST version with 16bit int */
+
+#include "machines/m68k/machine.c"
diff --git a/machines/m68ks/machine.dt b/machines/m68ks/machine.dt
new file mode 100755
index 0000000..44544a2
--- /dev/null
+++ b/machines/m68ks/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/m68ks/machine.h b/machines/m68ks/machine.h
new file mode 100755
index 0000000..ac3ee6a
--- /dev/null
+++ b/machines/m68ks/machine.h
@@ -0,0 +1,14 @@
+/* Code generator for Motorola 680x0 CPUs. Supports 68000-68060+68881/2 */
+/* and ColdFire. */
+/* PhxAss and the GNU assembler is supported. */
+
+/* stub for ST version with 16bit int */
+
+#define M68K_16BIT_INT
+
+#define PTRDIFF_T(x) LONG
+
+#define BESTCOPYT LONG
+
+#include "dt.h"
+#include "../m68k/machine.h"
diff --git a/machines/mark/machine.c b/machines/mark/machine.c
new file mode 100644
index 0000000..f4859dc
--- /dev/null
+++ b/machines/mark/machine.c
@@ -0,0 +1,1526 @@
+#include "supp.h"
+//#define DEBUG_MARK
+
+static char FILE_[]=__FILE__;
+
+//#include "version.h"
+char cg_copyright[]="not for public release";
+
+int g_flags[MAXGF]={};
+char *g_flags_name[MAXGF]={};
+union ppi g_flags_val[MAXGF];
+
+struct reg_handle empty_reg_handle={0};
+
+extern int handle_pragma(const char * c){return 0;}
+
+//support for ISR
+char *g_attr_name[] = {"__interrupt", 0};
+#define INTERRUPT 1
+
+/*
+ * Define registers codes
+ */
+
+#define R0 1 //zero register
+#define R1 2 //reserved for compiler
+#define R2 3 //reserved for compiler
+#define R3 4 //reserved for compiler
+#define R4 5 //condition codes
+#define R5 6 //return value
+#define R6 7
+#define R7 8
+#define R8 9
+#define R9 10
+#define R10 11
+#define R11 12
+#define R12 13
+#define FP 14 //frame pointer
+#define PC 15 //program counter
+#define SP 16 //stack pointer
+
+/*
+ * Custom function
+ */
+
+//evalue compare IC and prepare condition codes in R3 (COMPARE IC is followed by BRANCH allways)
+void compare(FILE *f, struct IC *p);
+//helper function for loading obj o into register dest_reg
+void load_into_reg(FILE *f, int dest_reg, struct obj *o, int type, int tmp_reg);
+//store reg into obj o
+void store_from_reg(FILE *f, int source_reg, struct obj *o, int type, int tmp_reg, int tmp_reg_b);
+//take care about all arithmetic IC
+void arithmetic(FILE *f, struct IC *p);
+//load constant into register
+void load_cons(FILE *f, int reg, long int value);
+
+/*
+ * Data Types
+ */
+zmax char_bit; // CHAR_BIT for the target machine.
+zmax align[MAX_TYPE+1]; // Alignment-requirements for all types in bytes.
+zmax maxalign; // Alignment that is sufficient for every object.
+zmax sizetab[MAX_TYPE+1]; // sizes of the basic types (in bytes)
+
+// Minimum and Maximum values each type can have.
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+
+/*
+ * Register Set
+ */
+
+/*
+ * Names of all registers. will be initialized in init_cg(),
+ * register number 0 is invalid, valid registers start at 1
+ */
+char *regnames[MAXR+1];
+
+/*
+ * The Size of each register in bytes.
+ */
+zmax regsize[MAXR+1];
+
+/*
+ * Specifies which registers may be scratched by functions.
+ */
+int regscratch[MAXR+1];
+
+/*
+ * a type which can store each register.
+ */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should
+ * not be used by the compiler pass.
+ */
+int regsa[MAXR+1];
+
+/*
+ * specifies the priority for the register-allocator, if the same
+ * estimated cost-saving can be obtained by several registers, the
+ * one with the highest priority will be used
+ */
+int reg_prio[MAXR+1];
+
+
+/*
+ * Does necessary initializations for the code-generator. Gets called
+ * once at the beginning and should return 0 in case of problems.
+ */
+int init_cg(void){
+
+ #ifdef DEBUG_MARK
+ printf("Called init_cg()\n");
+ #endif
+
+ int i;
+
+ maxalign=l2zm(1L);
+ char_bit=l2zm(32L);
+
+ for(i=0;i<=MAX_TYPE;i++){
+ align[i] = l2zm(1L);
+ sizetab[i] = l2zm(1L);
+ }
+
+ t_min[CHAR] = zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[SHORT] = t_min[CHAR];
+ t_min[INT] = t_min[CHAR];
+ t_min[LONG] = t_min[CHAR];
+ t_min[LLONG] = t_min[CHAR];
+ t_min[MAXINT] = t_min[CHAR];
+
+ t_max[CHAR] = ul2zum(2147483647UL);
+ t_max[SHORT] = t_max[CHAR];
+ t_max[INT] = t_max[CHAR];
+ t_max[LONG] = t_max[CHAR];
+ t_max[LLONG] = t_max[CHAR];
+ t_max[MAXINT] = t_max[CHAR];
+
+ tu_max[CHAR]=ul2zum(4294967295UL);
+ tu_max[SHORT] = tu_max[CHAR];
+ tu_max[INT] = tu_max[CHAR];
+ tu_max[LONG] = tu_max[CHAR];
+ tu_max[LLONG] = tu_max[CHAR];
+ tu_max[MAXINT] = tu_max[CHAR];
+
+
+ regnames[0] = "noreg";
+ reg_prio[0] = 0;
+ regscratch[0] = 0;
+ regsa[0] = 0;
+
+ //zero register
+ regnames[1] = "R0";
+ reg_prio[1] = 0;
+ regscratch[1] = 0;
+ regsa[1] = 1;
+
+ //R1 reserved for backed
+ regnames[2] = "R1";
+ reg_prio[2] = 0;
+ regscratch[2] = 0;
+ regsa[2] = 1;
+
+ //R2 reserved for backed
+ regnames[3] = "R2";
+ reg_prio[3] = 0;
+ regscratch[3] = 0;
+ regsa[3] = 1;
+
+ //R3 reserved for backed
+ regnames[4] = "R3";
+ reg_prio[4] = 0;
+ regscratch[4] = 0;
+ regsa[4] = 1;
+
+ //R4 condition codes
+ regnames[5] = "R4";
+ reg_prio[5] = 0;
+ regscratch[5] = 0;
+ regsa[5] = 1;
+
+ //R5 return value for function
+ regnames[6] = "R5";
+ reg_prio[6] = 0;
+ regscratch[6] = 0;
+ regsa[6] = 1;
+
+ regnames[7] = "R6";
+ reg_prio[7] = 0;
+ regscratch[7] = 0;
+ regsa[7] = 0;
+
+ regnames[8] = "R7";
+ reg_prio[8] = 0;
+ regscratch[8] = 0;
+ regsa[8] = 0;
+
+ regnames[9] = "R8";
+ reg_prio[9] = 0;
+ regscratch[9] = 0;
+ regsa[9] = 0;
+
+ regnames[10] = "R9";
+ reg_prio[10] = 0;
+ regscratch[10] = 0;
+ regsa[10] = 0;
+
+ regnames[11] = "R10";
+ reg_prio[11] = 0;
+ regscratch[11] = 0;
+ regsa[11] = 0;
+
+ regnames[12] = "R11";
+ reg_prio[12] = 0;
+ regscratch[12] = 0;
+ regsa[12] = 0;
+
+ regnames[13] = "R12";
+ reg_prio[13] = 0;
+ regscratch[13] = 0;
+ regsa[13] = 0;
+
+ // Frame pointer
+ regnames[FP] = "R13";
+ reg_prio[14] = 0;
+ regscratch[14] = 0;
+ regsa[14] = 1;
+
+ // Program counter
+ regnames[15] = "PC";
+ reg_prio[15] = 0;
+ regscratch[15] = 0;
+ regsa[15] = 1;
+
+ // Stack pointer
+ regnames[16] = "SP";
+ reg_prio[16] = 0;
+ regscratch[16] = 0;
+ regsa[16] = 1;
+
+
+ for(i=0;i<=MAXR;i++){
+ regsize[i] = l2zm(1L);
+ }
+
+ // Use multiple ccs
+ multiple_ccs = 0;
+
+ return 1;
+}
+
+void cleanup_cg(FILE *f){
+ #ifdef DEBUG_MARK
+ printf("Called cleanup_cg()\n");
+ #endif
+}
+
+/*
+ * Returns the register in which variables of type t are returned.
+ * If the value cannot be returned in a register returns 0.
+ */
+int freturn(struct Typ *t){
+ return R5;
+}
+
+/*
+ * Returns 0 if register r cannot store variables of
+ * type t. If t==POINTER and mode!=0 then it returns
+ * non-zero only if the register can store a pointer
+ * and dereference a pointer to mode.
+ */
+int regok(int r,int t,int mode){
+ return 1;
+}
+
+/*
+ * Returns zero if the IC p can be safely executed
+ * without danger of exceptions or similar things.
+ * vbcc may generate code in which non-dangerous ICs
+ * are sometimes executed although control-flow may
+ * never reach them (mainly when moving computations
+ * out of loops).
+ * Typical ICs that generate exceptions on some
+ * machines are:
+ * - accesses via pointers
+ * - division/modulo
+ * - overflow on signed integer/floats
+ */
+int dangerous_IC(struct IC *p){
+ return 0;
+}
+
+/*
+ * Returns zero if code for converting np to type t
+ * can be omitted.
+ * On the PowerPC cpu pointers and 32bit
+ * integers have the same representation and can use
+ * the same registers.
+ */
+int must_convert(int o,int t,int const_expr){
+ return 0;
+}
+
+int shortcut(int code,int typ){
+ return 0;
+}
+
+/*
+ * The main code-generation routine.
+ * f is the stream the code should be written to.
+ * p is a pointer to a doubly linked list of ICs
+ * containing the function body to generate code for.
+ * v is a pointer to the function.
+ * offset is the size of the stackframe the function
+ * needs for local variables.
+ */
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset){
+ #ifdef DEBUG_MARK
+ printf("Called gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)\n");
+ printf("\tIdentifier: %s", v->identifier);
+ #endif
+
+ //emit function head
+ if(v->storage_class==EXTERN){
+ if( (v->flags & (INLINEFUNC|INLINEEXT)) != INLINEFUNC ){
+ emit(f,".EXPORT \t %s \n",v->identifier);
+ }
+ emit(f,"%s: \n",v->identifier);
+ }
+ else{
+ emit(f,"L_%ld:\n",zm2l(v->offset));
+ }
+
+ //emit function prologue
+ emit(f, "\tPUSH \t %s\n", regnames[FP]); //push FP
+ emit(f, "\tOR \t %s %s %s\n",regnames[R0], regnames[SP], regnames[FP]); //MOVE SP -> FP
+
+ //make space for auto variables at stack
+ for(int i = 0; i < zm2l(offset); i++){
+ emit(f, "\tDEC \t %s %s\n", regnames[SP], regnames[SP]);
+ }
+
+ //store backend registers
+ emit(f, "\tPUSH \t R1\n\tPUSH \t R2\n\tPUSH \t R3\n\tPUSH \t R4\n");
+
+ //find used registers
+ int saved_regs[7] = {0, 0, 0, 0, 0, 0, 0};
+
+ struct IC *ps = p;
+ for(;ps;ps=ps->next){
+ if( ((ps->code) != FREEREG) && ((ps->code) != ALLOCREG) ){
+ if(((ps->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG){
+ if(((ps->q1.reg) > R5) && ((ps->q1.reg) < FP)){
+ saved_regs[(ps->q1.reg) - 7] = 1;
+ }
+ }
+ if(((ps->q2.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG){
+ if(((ps->q2.reg) > R5) && ((ps->q2.reg) < FP)){
+ saved_regs[(ps->q2.reg) - 7] = 1;
+ }
+ }
+ if(((ps->z.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG){
+ if(((ps->z.reg) > R5) && ((ps->z.reg) < FP)){
+ saved_regs[(ps->z.reg) - 7] = 1;
+ }
+ }
+ }
+ }
+
+ //save used registers
+ for(int i = 0; i < 7; i++){
+ if(saved_regs[i] == 1){
+ emit(f, "\tPUSH \t %s\n", regnames[i + 7]);
+ }
+ }
+
+ //emit function body
+ for(;p;p=p->next){
+ int c = p->code;
+
+ #ifdef DEBUG_MARK
+ emit(f, "\n\t;p->code: %d\n", p->code);
+ #endif
+
+ switch(p->code){
+ case ASSIGN:
+ #ifdef DEBUG_MARK
+ printf("\n\tASSIGN\n\tz.flags:%d\tq1.flags:%d\ttypf:%d\n", p->z.flags, p->q1.flags, p->typf);
+ #endif
+
+ //we can simplify assign when both operands are in registers
+ if((((p->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG) &&
+ (((p->z.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG) ){
+ emit(f, "\tOR \t %s %s %s",regnames[R0], regnames[p->q1.reg], regnames[p->z.reg]);
+ }
+
+ //this is another optimalization, if have to assign zero; then
+ //zero is read from R0 insted pushing constant into register
+ else if(
+ (((p->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == KONST) &&
+ ((p->q1.val.vmax) == 0)
+ ){
+ store_from_reg(f, R0, &(p->z), p->typf, R2, R3);
+ }
+
+ else{
+ load_into_reg(f, R1, &(p->q1), p->typf, R2);
+ store_from_reg(f, R1, &(p->z), p->typf, R2, R3);
+ }
+
+ break;
+ case OR:
+ #ifdef DEBUG_MARK
+ printf("\n\tOR\n");
+ #endif
+ arithmetic(f, p);
+ break;
+ case XOR:
+ #ifdef DEBUG_MARK
+ printf("\n\tXOR\n");
+ #endif
+ arithmetic(f, p);
+ break;
+ case AND:
+ #ifdef DEBUG_MARK
+ printf("\n\tAND\n");
+ #endif
+ arithmetic(f, p);
+ break;
+ case LSHIFT:
+ #ifdef DEBUG_MARK
+ printf("\n\tLSHIFT\n");
+ #endif
+ arithmetic(f, p);
+ break;
+ case RSHIFT:
+ #ifdef DEBUG_MARK
+ printf("\n\tRSHIFT\n");
+ #endif
+ arithmetic(f, p);
+ break;
+ case ADD:
+ #ifdef DEBUG_MARK
+ printf("\n\tADD\n");
+ #endif
+ arithmetic(f, p);
+ break;
+ case SUB:
+ #ifdef DEBUG_MARK
+ printf("\n\tSUB\n");
+ #endif
+ arithmetic(f, p);
+ break;
+ case MULT:
+ #ifdef DEBUG_MARK
+ printf("\n\tMULT\n");
+ #endif
+ arithmetic(f, p);
+ break;
+ case DIV:
+ #ifdef DEBUG_MARK
+ printf("\n\tDIV\n");
+ #endif
+ arithmetic(f, p);
+ break;
+ case MOD:
+ #ifdef DEBUG_MARK
+ printf("\n\tMOD\n");
+ #endif
+ arithmetic(f, p);
+ break;
+ case KOMPLEMENT:
+ #ifdef DEBUG_MARK
+ printf("\n\tKOMPLEMENT\n");
+ #endif
+ arithmetic(f, p);
+ break;
+ case MINUS:
+ #ifdef DEBUG_MARK
+ printf("\n\tMINUS\n");
+ #endif
+ arithmetic(f, p);
+ break;
+ case ADDRESS:
+ #ifdef DEBUG_MARK
+ printf("\n\tADDRESS\n");
+ #endif
+
+ if(
+ (((p->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == VAR) &&
+ (((p->q1.v->storage_class) & (AUTO|REGISTER|STATIC|EXTERN)) == AUTO)
+ ){
+ if(ISARRAY(p->q1.v->flags)){
+ load_cons(f, R1, zm2l(p->q1.v->offset)+zm2l(p->q1.val.vmax));
+ }
+ else{
+ load_cons(f, R1, zm2l(p->q1.v->offset));
+ }
+ emit(f, "\tADD \t R1 R13 R1\n");
+ store_from_reg(f, R1, &(p->z), p->typf, R2, R3);
+ }
+ else{
+ ierror(0);
+ }
+
+ break;
+ case CALL:
+ #ifdef DEBUG_MARK
+ printf("\n\tCALL\n\tq1.flags: %d\n", p->q1.flags);
+ #endif
+
+ if((p->q1.flags & (VAR|DREFOBJ)) == VAR && p->q1.v->fi && p->q1.v->fi->inline_asm){
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ }
+ else{
+
+ if(((p->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == VAR){
+
+ #ifdef DEBUG_MARK
+ printf("\tq1.v->storage_class: %d\n", p->q1.v->storage_class);
+ #endif
+
+ switch((p->q1.v->storage_class) & (AUTO|REGISTER|STATIC|EXTERN)){
+ case EXTERN:
+ emit(f, "\tCALL \t %s\n", p->q1.v->identifier);
+ for(int i = 0; i < (p->q2.val.vmax); i++){
+ emit(f, "\tINC \t %s %s\n", regnames[SP], regnames[SP]);
+ }
+ break;
+ case STATIC:
+ emit(f, "\tCALL \t L_%ld\n", zm2l(p->q1.v->offset));
+ for(int i = 0; i < (p->q2.val.vmax); i++){
+ emit(f, "\tINC \t %s %s\n", regnames[SP], regnames[SP]);
+ }
+ break;
+ default:
+ #ifdef DEBUG_MARK
+ printf("\tThis is not implemented!\n");
+ #else
+ ierror(0);
+ #endif
+ break;
+ }
+
+ }
+ else if(((p->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == (VAR|DREFOBJ)){
+ #ifdef DEBUG_MARK
+ printf("\tq1.v->storage_class: %d\n", p->q1.v->storage_class);
+ #endif
+ load_into_reg(f, R1, &(p->q1), p->typf, R3);
+ emit(f, "\tCALLI\t %s\n", regnames[R1]);
+ emit(f, "\tINC \t %s %s\n", regnames[SP], regnames[SP]);
+ }
+ else{
+ #ifdef DEBUG_MARK
+ printf("\tThis is not implemented!\n");
+ #else
+ ierror(0);
+ #endif
+ }
+ }
+ break;
+ case CONVERT:
+ #ifdef DEBUG_MARK
+ printf("\n\tCONVERT\n");
+ #endif
+
+ break;
+ case ALLOCREG:
+ #ifdef DEBUG_MARK
+ printf("\n\tALLOCREG\n");
+ #endif
+
+ regs[p->q1.reg] = 1;
+ break;
+ case FREEREG:
+ #ifdef DEBUG_MARK
+ printf("\n\tFREEREG\n");
+ #endif
+
+ regs[p->q1.reg] = 0;
+ break;
+ case COMPARE:
+ #ifdef DEBUG_MARK
+ printf("\n\tCOMPARE\n");
+ #endif
+
+ compare(f, p);
+ break;
+ case TEST:
+ #ifdef DEBUG_MARK
+ printf("\n\tTEST\n");
+ #endif
+
+ compare(f, p);
+ break;
+ case LABEL:
+ #ifdef DEBUG_MARK
+ printf("\n\tLABEL\n");
+ #endif
+
+ emit(f,"L_%d:\n",p->typf);
+ break;
+ case BEQ:
+ #ifdef DEBUG_MARK
+ printf("\n\tBEQ\n");
+ #endif
+
+ emit(f, "\tBNZ \t R4 L_%d\n", p->typf);
+ break;
+ case BNE:
+ #ifdef DEBUG_MARK
+ printf("\n\tBNE\n");
+ #endif
+
+ emit(f, "\tBNZ \t R4 L_%d\n", p->typf);
+ break;
+ case BLT:
+ #ifdef DEBUG_MARK
+ printf("\n\tBLT\n");
+ #endif
+
+ emit(f, "\tBNZ \t R4 L_%d\n", p->typf);
+ break;
+ case BGE:
+ #ifdef DEBUG_MARK
+ printf("\n\tBGE\n");
+ #endif
+
+ emit(f, "\tBNZ \t R4 L_%d\n", p->typf);
+ break;
+ case BLE:
+ #ifdef DEBUG_MARK
+ printf("\n\tBLE\n");
+ #endif
+
+ emit(f, "\tBNZ \t R4 L_%d\n", p->typf);
+ break;
+ case BGT:
+ #ifdef DEBUG_MARK
+ printf("\n\tBGT\n");
+ #endif
+
+ emit(f, "\tBNZ \t R4 L_%d\n", p->typf);
+ break;
+ case BRA:
+ #ifdef DEBUG_MARK
+ printf("\n\tBRA\n");
+ #endif
+
+ emit(f, "\tBZ \t R0 L_%d\n", p->typf);
+ break;
+ case PUSH:
+ #ifdef DEBUG_MARK
+ printf("\n\tPUSH\n");
+ #endif
+
+ load_into_reg(f, R1, &(p->q1), p->typf, R2);
+ emit(f, "\tPUSH \t R1\n");
+ break;
+ case ADDI2P:
+ #ifdef DEBUG_MARK
+ printf("\n\tADDI2P\n");
+ #endif
+ arithmetic(f, p);
+ break;
+ case SUBIFP:
+ #ifdef DEBUG_MARK
+ printf("\n\tSUBIFP\n");
+ #endif
+ arithmetic(f, p);
+ break;
+ case SUBPFP:
+ #ifdef DEBUG_MARK
+ printf("\n\tSUBPFP\n");
+ #endif
+ arithmetic(f, p);
+ break;
+ case GETRETURN:
+ #ifdef DEBUG_MARK
+ printf("\n\tGETRETURN\n");
+ #endif
+ if((p->q1.reg) != 0){
+ store_from_reg(f, p->q1.reg, &(p->z), p->typf, R2, R3);
+ }
+ else{
+ #ifdef DEBUG_MARK
+ printf("\tq1.reg == 0, didn't know how to dealt with it!");
+ #else
+ ierror(0);
+ #endif
+ }
+ break;
+ case SETRETURN:
+ #ifdef DEBUG_MARK
+ printf("\n\tSETRETURN\n\tz.flags:%d\n", p->z.flags);
+ #endif
+ if((p->z.reg) != 0){
+ load_into_reg(f, p->z.reg, &(p->q1), p->typf, R1);
+ }
+ else{
+ #ifdef DEBUG_MARK
+ printf("\tz.reg == 0, didn't know how to dealt with it!");
+ #else
+ ierror(0);
+ #endif
+ }
+ break;
+ case MOVEFROMREG:
+ #ifdef DEBUG_MARK
+ printf("\n\tMOVEFROMREG\n");
+ #endif
+
+ store_from_reg(f, p->q1.reg, &(p->z), p->typf, R1, R3);
+ break;
+ case MOVETOREG:
+ #ifdef DEBUG_MARK
+ printf("\n\tMOVETOREG\n");
+ #endif
+
+ load_into_reg(f, p->z.reg, &(p->q1), p->typf, R1);
+ break;
+ case NOP:
+ #ifdef DEBUG_MARK
+ printf("\n\tNOP\n");
+ #endif
+ break;
+ default:
+ #ifdef DEBUG_MARK
+ printf("\tSomething is wrong in gencode()!\n");
+ #else
+ ierror(0);
+ #endif
+ break;
+ }
+ }
+
+ //restore used registers
+ for(int i = 6; i >= 0; i--){
+ if(saved_regs[i] == 1){
+ emit(f, "\tPOP \t %s\n", regnames[i + 7]);
+ }
+ }
+
+ //restore backend registers
+ emit(f, "\tPOP \t R4\n\tPOP \t R3\n\tPOP \t R2\n\tPOP \t R1\n");
+
+ //emit function epilogue
+ emit(f, "\tOR \t %s %s %s\n",regnames[R0], regnames[FP], regnames[SP]); //restore SP from FP
+ emit(f, "\tPOP \t %s\n", regnames[FP]); //restore old FP from stack
+
+ //return
+ if((v->tattr)&INTERRUPT){
+ emit(f, "\tRETI\n");
+ }
+ else{
+ emit(f, "\tRET\n");
+ }
+}
+
+/*
+ * This function has to create <size> bytes of storage
+ * initialized with zero.
+ */
+void gen_ds(FILE *f,zmax size,struct Typ *t){
+ #ifdef DEBUG_MARK
+ printf("Called gen_ds(FILE *f,zmax size,struct Typ *t)\n");
+ #endif
+ emit(f, "\t.DS \t%ld\n", zm2l(size));
+}
+
+/*
+ * This function has to make sure the next data is
+ * aligned to multiples of <align> bytes.
+ */
+void gen_align(FILE *f,zmax align){}
+
+/*
+ * This function has to create the head of a variable
+ * definition, i.e. the label and information for
+ * linkage etc.
+ */
+void gen_var_head(FILE *f,struct Var *v){
+ #ifdef DEBUG_MARK
+ printf("Called gen_var_head(FILE *f,struct Var *v)\n");
+ #endif
+
+ switch((v->storage_class) & (STATIC|EXTERN|AUTO|REGISTER)){
+ case STATIC:
+ #ifdef DEBUG_MARK
+ printf("\tHave to emit static variable head.\n");
+ #endif
+ emit(f,"L_%ld:\n", zm2l(v->offset));
+ break;
+ case EXTERN:
+ #ifdef DEBUG_MARK
+ printf("\tHave to emit extern variable head.\n");
+ #endif
+
+ if(v->flags&(DEFINED|TENTATIVE)){
+ emit(f,".EXPORT \t %s\n", v->identifier);
+ emit(f,"%s:\n", v->identifier);
+ }
+ else{
+ emit(f,".IMPORT \t %s\n", v->identifier);
+ }
+ break;
+ default:
+ #ifdef DEBUG_MARK
+ printf("\tCant generate head, unknown storage class: %d\n", v->storage_class);
+ #else
+ ierror(0);
+ #endif
+ break;
+ }
+}
+
+/*
+ * This function has to create static storage
+ * initialized with const-list p.
+ */
+void gen_dc(FILE *f,int t,struct const_list *p){
+ #ifdef DEBUG_MARK
+ printf("Called gen_dc(FILE *f,int t,struct const_list *p)\n");
+ #endif
+
+ if(!p->tree){
+ if(ISFLOAT(t)){
+ emit(f,"\t.DAT \t ");
+ emit(f,"0x%x", *(unsigned int*)&p->val);
+ emit(f,"\n");
+ }
+ else{
+ emit(f,"\t.DAT \t ");
+ emitval(f,&p->val,t&NU);
+ emit(f,"\n");
+ }
+ }
+ else{
+ emit(f,"\t.DAT \t ");
+ struct const_list *p_next = p;
+ for(;p_next;p_next=p_next->next){
+ emitval(f,&p_next->val,t&NU);
+ emit(f, " ");
+ }
+ emit(f, "\n");
+ }
+}
+
+//this is for debug, not needed now
+void init_db(FILE *f){}
+void cleanup_db(FILE *f){}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d){
+ //this will put all arguments into stack
+ return 0;
+}
+
+/*
+ * Returns 0 if the register is no register pair. If r
+ * is a register pair non-zero will be returned and the
+ * structure pointed to p will be filled with the two
+ * elements.
+ */
+int reg_pair(int r,struct rpair *p){
+ return 0;
+}
+
+void compare(FILE *f, struct IC *p){
+
+ int q1reg = 0;
+ int q2reg = 0;
+
+ //load operands into R1 and R2
+ if(((p->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) != REG){
+ load_into_reg(f, R1, &(p->q1), p->typf, R3);
+ q1reg = R1;
+ }
+ else{
+ q1reg = p->q1.reg;
+ }
+
+ if((p->code) != TEST){
+ if(((p->q2.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) != REG){
+ load_into_reg(f, R2, &(p->q2), p->typf, R3);
+ q2reg = R2;
+ }
+ else{
+ q2reg = p->q2.reg;
+ }
+ }
+ else{
+ q2reg = R2;
+ emit(f, "\tOR \t %s %s %s\n",regnames[R0], regnames[R0], regnames[R2]);
+ }
+
+ //find branch IC
+ struct IC *branch_ic;
+ branch_ic = p->next;
+ while(branch_ic && ((branch_ic->code) == FREEREG) ) {
+ branch_ic = branch_ic->next;
+ }
+
+ //emit compare code
+ if (((p->typf) & FLOAT) == FLOAT || ((p->typf) & DOUBLE) == DOUBLE || ((p->typf) & LDOUBLE) == LDOUBLE){
+ switch(branch_ic->code){
+ case BEQ:
+ emit(f, "\tCMPF \t EQ %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ break;
+ case BNE:
+ emit(f, "\tCMPF \t NEQ %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ break;
+ case BLT:
+ emit(f, "\tCMPF \t L %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ break;
+ case BGE:
+ emit(f, "\tCMPF \t GE %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ break;
+ case BLE:
+ emit(f, "\tCMPF \t LE %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ break;
+ case BGT:
+ emit(f, "\tCMPF \t G %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ break;
+ default:
+ ierror(0);
+ break;
+ }
+ }
+ else{
+ switch(branch_ic->code){
+ case BEQ:
+ emit(f, "\tCMPI \t EQ %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ break;
+ case BNE:
+ emit(f, "\tCMPI \t NEQ %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ break;
+ case BLT:
+ if((p->typf & UNSIGNED) == UNSIGNED){
+ emit(f, "\tCMPI \t LU %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ }
+ else{
+ emit(f, "\tCMPI \t L %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ }
+ break;
+ case BGE:
+ if((p->typf & UNSIGNED) == UNSIGNED){
+ emit(f, "\tCMPI \t GEU %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ }
+ else{
+ emit(f, "\tCMPI \t GE %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ }
+ break;
+ case BLE:
+ if((p->typf & UNSIGNED) == UNSIGNED){
+ emit(f, "\tCMPI \t LEU %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ }
+ else{
+ emit(f, "\tCMPI \t LE %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ }
+ break;
+ case BGT:
+ if((p->typf & UNSIGNED) == UNSIGNED){
+ emit(f, "\tCMPI \t GU %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ }
+ else{
+ emit(f, "\tCMPI \t G %s %s R4\n", regnames[q1reg], regnames[q2reg]);
+ }
+ break;
+ default:
+ ierror(0);
+ break;
+ }
+ }
+}
+
+void load_into_reg(FILE *f, int dest_reg, struct obj *o, int type, int tmp_reg){
+ switch((o->flags) & (KONST|VAR|REG|DREFOBJ|VARADR)){
+ case KONST:
+ load_cons(f, dest_reg, o->val.vmax);
+ break;
+ case (KONST|DREFOBJ):
+ //place memory location constant point to into register
+ emit(f, "\tLD \t ");
+ emitval(f, &(o->val), type);
+ emit(f, " %s\n", regnames[dest_reg]);
+ break;
+ case REG:
+ //move between registers
+ if((o->reg) != dest_reg){
+ emit(f, "\tOR \t %s %s %s\n",regnames[R0], regnames[o->reg], regnames[dest_reg]);
+ }
+ break;
+ case VAR:
+ //put value of variable into register
+
+ switch((o->v->storage_class) & (STATIC|EXTERN|AUTO|REGISTER)){
+ case STATIC:
+ if(zm2l(o->val.vmax) != 0){
+ emit(f, "\tMVIA \t %s L_%ld\n", regnames[dest_reg], zm2l(o->v->offset));
+ load_cons(f, tmp_reg, zm2l(o->val.vmax));
+ emit(f, "\tADD \t %s %s %s\n", regnames[dest_reg], regnames[tmp_reg], regnames[tmp_reg]);
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+ }
+ else{
+ emit(f, "\tLD \t L_%ld %s\n", zm2l(o->v->offset), regnames[dest_reg]);
+ }
+ break;
+ case EXTERN:
+ if(zm2l(o->val.vmax) != 0){
+ emit(f, "\tMVIA \t %s %s\n", regnames[dest_reg], o->v->identifier);
+ load_cons(f, tmp_reg, zm2l(o->val.vmax));
+ emit(f, "\tADD \t %s %s %s\n", regnames[dest_reg], regnames[tmp_reg], regnames[tmp_reg]);
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+ }
+ else{
+ emit(f, "\tLD \t %s %s\n", o->v->identifier , regnames[dest_reg]);
+ }
+ break;
+ case AUTO:
+ if((o->v->offset) < 0){
+ //this is argument
+ load_cons(f, dest_reg, (zm2l(o->v->offset)/(-1L))+2+zm2l(o->val.vmax));
+ emit(f, "\tADD \t %s %s %s\n", regnames[dest_reg],regnames[FP], regnames[tmp_reg]);
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+ }
+ else{
+ //this is auto variable
+ int offset = zm2l(o->v->offset)+zm2l(o->val.vmax);
+
+ if(offset == 0){
+ emit(f, "\tLDI \t %s %s\n", regnames[FP], regnames[dest_reg]);
+ }
+ else if(offset == 1){
+ emit(f, "\tDEC \t %s %s\n", regnames[FP], regnames[tmp_reg]);
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+ }
+ else{
+ load_cons(f, dest_reg, offset);
+ emit(f, "\tSUB \t %s %s %s\n", regnames[FP],regnames[dest_reg], regnames[tmp_reg]);
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+ }
+
+ }
+ break;
+ default:
+ #ifdef DEBUG_MARK
+ printf("\tHave to load variable that is not static, extern or auto, this is not implemented!\n");
+ #else
+ ierror(0);
+ #endif
+ break;
+ }
+
+ break;
+ case (VAR|REG):
+ if((o->reg) != dest_reg){
+ emit(f, "\tOR \t %s %s %s\n", regnames[R0], regnames[o->reg], regnames[dest_reg]);
+ }
+ break;
+ case (REG|DREFOBJ):
+ //point into memory with register value
+
+ emit(f, "\tLDI \t %s %s\n", regnames[o->reg], regnames[dest_reg]);
+ break;
+ case (VAR|DREFOBJ):
+ //use variable value as pointer to memory
+
+ switch((o->v->storage_class) & (STATIC|EXTERN|AUTO|REGISTER)){
+ case STATIC:
+ if(zm2l(o->val.vmax) != 0){
+ emit(f, "\tMVIA \t %s L_%ld\n", regnames[dest_reg], zm2l(o->v->offset));
+ load_cons(f, tmp_reg, zm2l(o->val.vmax));
+ emit(f, "\tADD \t %s %s %s\n", regnames[dest_reg], regnames[tmp_reg], regnames[dest_reg]);
+ emit(f, "\tLDI \t %s %s\n", regnames[dest_reg], regnames[tmp_reg]);
+ }
+ else{
+ emit(f, "\tLD \t L_%ld %s\n", zm2l(o->v->offset), regnames[tmp_reg]);
+ }
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+ break;
+ case EXTERN:
+ if(zm2l(o->val.vmax) != 0){
+ emit(f, "\tMVIA \t %s %s\n", regnames[dest_reg], o->v->identifier);
+ load_cons(f, tmp_reg, zm2l(o->val.vmax));
+ emit(f, "\tADD \t %s %s %s\n", regnames[dest_reg], regnames[tmp_reg], regnames[dest_reg]);
+ emit(f, "\tLDI \t %s %s\n", regnames[dest_reg], regnames[tmp_reg]);
+ }
+ else{
+ emit(f, "\tLD \t %s %s\n", o->v->identifier , regnames[tmp_reg]);
+ }
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+ break;
+ case AUTO:
+ if((o->v->offset) < 0){
+ //this is argument
+ load_cons(f, dest_reg, (zm2l(o->v->offset)/(-1L))+2+zm2l(o->val.vmax));
+ emit(f, "\tADD \t %s %s %s\n", regnames[dest_reg],regnames[FP], regnames[tmp_reg]);
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+ }
+ else{
+ //this is auto variable
+ int offset = zm2l(o->v->offset)+zm2l(o->val.vmax);
+
+ if(offset == 0){
+ emit(f, "\tLDI \t %s %s\n", regnames[FP], regnames[dest_reg]);
+ }
+ else if(offset == 1){
+ emit(f, "\tDEC \t %s %s\n", regnames[FP], regnames[tmp_reg]);
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+ }
+ else{
+ load_cons(f, dest_reg, offset);
+ emit(f, "\tSUB \t %s %s %s\n", regnames[FP],regnames[dest_reg], regnames[tmp_reg]);
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+ }
+
+ }
+ break;
+ default:
+ #ifdef DEBUG_MARK
+ printf("\tHave to load variable that is not static, extern or auto, this is not implemented!\n");
+ #else
+ ierror(0);
+ #endif
+ break;
+ }
+
+ emit(f, "\tLDI \t %s %s\n", regnames[dest_reg], regnames[tmp_reg]);
+ emit(f, "\tOR \t R0 %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+
+ break;
+ case (VAR|REG|DREFOBJ):
+ if((o->reg) != dest_reg){
+ emit(f, "\tOR \t %s %s %s\n",regnames[R0], regnames[o->reg], regnames[tmp_reg]);
+ }
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[dest_reg]);
+ break;
+ case (VAR|VARADR):
+ //into dest_reg store address of variable
+ switch((o->v->storage_class) & (STATIC|EXTERN)){
+ case EXTERN:
+ emit(f, "\tMVIA \t %s %s\n", regnames[dest_reg], o->v->identifier);
+ break;
+ case STATIC:
+ emit(f, "\tMVIA \t %s L_%ld\n", regnames[dest_reg], zm2l(o->v->offset));
+ break;
+ default: //this is pointless storage_class can be only static or extern with VARADR
+ ierror(0);
+ }
+ //this is useful when object is array and we want adres of nonfirst element
+ if(o->val.vmax > 0){
+ load_cons(f, tmp_reg, o->val.vmax);
+ emit(f, "\tADD \t %s %s %s\n", regnames[dest_reg], regnames[tmp_reg], regnames[dest_reg]);
+ }
+
+ break;
+ default:
+ #ifdef DEBUG_MARK
+ printf("\tSomething is wrong while acuring operand!\n");
+ #else
+ ierror(0);
+ #endif
+ break;
+ }
+}
+
+void store_from_reg(FILE *f, int source_reg, struct obj *o, int type, int tmp_reg, int tmp_reg_b){
+ switch((o->flags) & (KONST|VAR|REG|DREFOBJ|VARADR)){
+ case KONST:
+ //How can I store register into KONST?!
+ ierror(0);
+ break;
+ case (KONST|DREFOBJ):
+ //use konstant as pointer into memory
+ emit(f, "\tST \t %s ", regnames[source_reg]);
+ emitval(f, &(o->val), type);
+ emit(f, "\n");
+ break;
+ case REG:
+ //move from register into register
+ if(source_reg != (o->reg)){
+ emit(f, "\tOR \t %s %s %s\n",regnames[R0], regnames[source_reg], regnames[o->reg]);
+ }
+ break;
+ case VAR:
+ //load register into variable
+ switch((o->v->storage_class) & (STATIC|EXTERN|AUTO|REGISTER)){
+ case STATIC:
+ if(zm2l(o->val.vmax) != 0){
+ emit(f, "\tMVIA \t %s L_%ld\n", regnames[tmp_reg], zm2l(o->v->offset));
+ load_cons(f, tmp_reg_b, zm2l(o->val.vmax));
+ emit(f, "\tADD \t %s %s %s\n", regnames[tmp_reg], regnames[tmp_reg_b], regnames[tmp_reg]);
+ emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+ }
+ else{
+ emit(f, "\tST \t %s L_%ld\n", regnames[source_reg], zm2l(o->v->offset));
+ }
+ break;
+ case EXTERN:
+ if(zm2l(o->val.vmax) != 0){
+ emit(f, "\tMVIA \t %s %s\n", regnames[tmp_reg], o->v->identifier);
+ load_cons(f, tmp_reg_b, zm2l(o->val.vmax));
+ emit(f, "\tADD \t %s %s %s\n", regnames[tmp_reg], regnames[tmp_reg_b], regnames[tmp_reg]);
+ emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+ }
+ else{
+ emit(f, "\tST \t %s %s\n", regnames[source_reg], o->v->identifier);
+ }
+ break;
+ case AUTO:
+ if((o->v->offset) < 0){
+ //function argument
+ load_cons(f, tmp_reg, (zm2l(o->v->offset)/(-1L))+2+zm2l(o->val.vmax));
+ emit(f, "\tADD \t %s %s %s\n", regnames[tmp_reg],regnames[FP], regnames[tmp_reg]);
+ emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+ }
+ else{
+ //auto variable
+ int offset = zm2l(o->v->offset)+zm2l(o->val.vmax);
+ if (offset == 0){
+ emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[FP]);
+ }
+ else if(offset == 1){
+ emit(f, "\tDEC \t %s %s\n", regnames[FP], regnames[tmp_reg]);
+ emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+ }
+ else{
+ load_cons(f, tmp_reg, offset);
+ emit(f, "\tSUB \t %s %s %s\n", regnames[FP],regnames[tmp_reg], regnames[tmp_reg]);
+ emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+ }
+ }
+ break;
+ default:
+ #ifdef DEBUG_MARK
+ printf("\tHave to store into variable that is not static, extern or auto, this is not implemented!\n");
+ #else
+ ierror(0);
+ #endif
+ break;
+ }
+ break;
+ case (VAR|REG):
+ emit(f, "\tOR \t %s %s %s\n", regnames[R0], regnames[source_reg], regnames[o->reg]);
+ break;
+ case (REG|DREFOBJ):
+ //use value in register as pointer into memory
+ emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[o->reg]);
+ break;
+ case (VAR|DREFOBJ):
+ //use value in variable as pointer into memory
+ switch((o->v->storage_class) & (STATIC|EXTERN|AUTO|REGISTER)){
+ case STATIC:
+ if(zm2l(o->val.vmax) != 0){
+ emit(f, "\tMVIA \t %s L_%ld\n", regnames[tmp_reg], zm2l(o->v->offset));
+ load_cons(f, tmp_reg_b, zm2l(o->val.vmax));
+ emit(f, "\tADD \t %s %s %s\n", regnames[tmp_reg], regnames[tmp_reg_b], regnames[tmp_reg_b]);
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg_b], regnames[tmp_reg]);
+ }
+ else{
+ emit(f, "\tLD \t L_%ld %s\n", zm2l(o->v->offset), regnames[tmp_reg]);
+ }
+ emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+ break;
+ case EXTERN:
+ if(zm2l(o->val.vmax) != 0){
+ emit(f, "\tMVIA \t %s %s\n", regnames[tmp_reg], o->v->identifier);
+ load_cons(f, tmp_reg_b, zm2l(o->val.vmax));
+ emit(f, "\tADD \t %s %s %s\n", regnames[tmp_reg], regnames[tmp_reg_b], regnames[tmp_reg_b]);
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg_b], regnames[tmp_reg]);
+ }
+ else{
+ emit(f, "\tLD \t %s %s\n", o->v->identifier, regnames[tmp_reg] );
+ }
+ emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+ break;
+ case AUTO:
+ if((o->v->offset) < 0){
+ //function argument
+ load_cons(f, tmp_reg, (zm2l(o->v->offset)/(-1L))+2+zm2l(o->val.vmax));
+ emit(f, "\tADD \t %s %s %s\n", regnames[tmp_reg],regnames[FP], regnames[tmp_reg_b]);
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg_b], regnames[tmp_reg]);
+ emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+ }
+ else{
+ //auto variable
+ int offset = zm2l(o->v->offset)+zm2l(o->val.vmax);
+ if(offset == 0){
+ emit(f, "\tLDI \t %s %s\n", regnames[FP], regnames[tmp_reg_b]);
+ }
+ else if(offset == 1){
+ emit(f, "\tDEC \t %s %s\n", regnames[FP], regnames[tmp_reg_b]);
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg_b], regnames[tmp_reg]);
+ }
+ else{
+ load_cons(f, tmp_reg, offset);
+ emit(f, "\tSUB \t %s %s %s\n", regnames[FP],regnames[tmp_reg], regnames[tmp_reg]);
+ emit(f, "\tLDI \t %s %s\n", regnames[tmp_reg], regnames[tmp_reg_b]);
+ }
+ emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg_b]);
+ }
+ break;
+ default:
+ #ifdef DEBUG_MARK
+ printf("\tHave to store into variable that is not static, extern or auto, this is not implemented!\n");
+ #else
+ ierror(0);
+ #endif
+ break;
+ }
+ break;
+ case (VAR|REG|DREFOBJ):
+ emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[o->reg]);
+ break;
+ case (VAR|VARADR): //use variable address as pointer
+ switch(o->v->storage_class){
+ case STATIC:
+ emit(f, "\tMVIA \t %s L_%ld\n", regnames[tmp_reg], zm2l(o->v->offset));
+ emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+ break;
+ case EXTERN:
+ emit(f, "\tMVIA \t %s %s\n", regnames[tmp_reg], o->v->identifier);
+ emit(f, "\tSTI \t %s %s\n", regnames[source_reg], regnames[tmp_reg]);
+ break;
+ default: //can be only static or extern
+ ierror(0);
+ break;
+ }
+ break;
+ default:
+ #ifdef DEBUG_MARK
+ printf("\tCant store reg into object, unknown object!\n");
+ #else
+ ierror(0);
+ #endif
+ break;
+ }
+}
+
+void arithmetic(FILE *f, struct IC *p){
+ int q1reg = 0;
+ int q2reg = 0;
+
+ int zreg = 0;
+ int movez = 0;
+
+ int unary = 0;
+
+ int isunsigned = 0;
+ if (((p->typf) & UNSIGNED) == UNSIGNED){
+ isunsigned = 1;
+ }
+
+ if(((p->code) == MINUS) || ((p->code) == KOMPLEMENT)){
+ unary = 1;
+ }
+
+ //load first operand
+ if(((p->q1.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG){
+ q1reg = p->q1.reg;
+ }
+ else{
+ load_into_reg(f, R1, &(p->q1), p->typf, R3);
+ q1reg = R1;
+ }
+
+ //load second operand
+ if(unary != 1){
+ if(((p->q2.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG){
+ q2reg = p->q2.reg;
+ }
+ else{
+ load_into_reg(f, R2, &(p->q2), p->typf, R3);
+ q2reg = R2;
+ }
+ }
+
+ //prepare target register
+ if(((p->z.flags) & (KONST|VAR|REG|DREFOBJ|VARADR)) == REG){
+ zreg = p->z.reg;
+ }
+ else{
+ zreg = R1;
+ movez = 1;
+ }
+
+ if (((p->typf) & FLOAT) == FLOAT || ((p->typf) & DOUBLE) == DOUBLE || ((p->typf) & LDOUBLE) == LDOUBLE){
+ switch(p->code){
+ case ADD:
+ emit(f, "\tFADD \t ");
+ break;
+ case SUB:
+ emit(f, "\tFSUB \t ");
+ break;
+ case MULT:
+ emit(f, "\tFMUL \t ");
+ break;
+ case DIV:
+ emit(f, "\tFDIV \t ");
+ break;
+ case MINUS:
+ load_cons(f, R2, 0x3f800000);
+ emit(f, "\tSUB \t ");
+ unary = 0;
+ q2reg = R2;
+ break;
+ default:
+ #ifdef DEBUG_MARK
+ printf("This is not implemented!\n");
+ #else
+ ierror(0);
+ #endif
+ break;
+ }
+ }
+ else{
+
+ //emit instruction opcode
+ switch(p->code){
+ case OR:
+ emit(f, "\tOR \t ");
+ break;
+ case XOR:
+ emit(f, "\tXOR \t ");
+ break;
+ case AND:
+ emit(f, "\tAND \t ");
+ break;
+ case LSHIFT:
+ emit(f, "\tLSL \t ");
+ break;
+ case RSHIFT:
+ if(isunsigned == 1) {
+ emit(f, "\tLSR \t ");
+ }
+ else{
+ emit(f, "\tASR \t ");
+ }
+ break;
+ case ADD:
+ emit(f, "\tADD \t ");
+ break;
+ case SUB:
+ emit(f, "\tSUB \t ");
+ break;
+ case MULT:
+ if(isunsigned == 1) {
+ emit(f, "\tMULU \t ");
+ }
+ else{
+ emit(f, "\tMUL \t ");
+ }
+ break;
+ case DIV:
+ if(isunsigned == 1) {
+ emit(f, "\tDIVU \t ");
+ }
+ else{
+ emit(f, "\tDIV \t ");
+ }
+ break;
+ case MOD:
+ if(isunsigned == 1) {
+ emit(f, "\tREMU \t ");
+ }
+ else{
+ emit(f, "\tREM \t ");
+ }
+ break;
+ case ADDI2P:
+ emit(f, "\tADD \t ");
+ break;
+ case SUBIFP:
+ emit(f, "\tSUB \t ");
+ break;
+ case SUBPFP:
+ emit(f, "\tSUB \t ");
+ break;
+ case MINUS:
+ emit(f, "\tDEC \t ");
+ break;
+ case KOMPLEMENT:
+ emit(f, "\tNOT \t ");
+ break;
+ default:
+ #ifdef DEBUG_MARK
+ printf("\tPassed invalid IC into arithmetic()\n\tp->code: %d\n", p->code);
+ #else
+ ierror(0);
+ #endif
+ break;
+ }
+ }
+
+ //emit instruction arguments
+ if(unary != 1){
+ emit(f, "%s %s %s\n", regnames[q1reg], regnames[q2reg], regnames[zreg]);
+ }
+ else{
+ emit(f, "%s %s\n", regnames[q1reg], regnames[zreg]);
+ }
+
+ if(movez == 1){
+ store_from_reg(f, R1, &(p->z), p->typf, R2, R3);
+ }
+}
+
+void load_cons(FILE *f, int reg, long int value){
+ if(value == 0){
+ emit(f, "\tOR \t R0 R0 %s\n", regnames[reg]);
+ }
+ else if((16777216 > value) && (value > 0)){
+ emit(f, "\tMVIA \t %s %ld\n", regnames[reg], value);
+ }
+ else if (value > 0){
+ emit(f, "\t.MVI \t %s %ld\n", regnames[reg], value);
+ }
+ else{
+ emit(f, "\t.MVI \t %s 0x%x\n", regnames[reg], value);
+ }
+}
diff --git a/machines/mark/machine.dt b/machines/mark/machine.dt
new file mode 100644
index 0000000..230a53c
--- /dev/null
+++ b/machines/mark/machine.dt
@@ -0,0 +1,15 @@
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S32BIEEELE S32BIEEEBE
+S32BIEEELE S32BIEEEBE
+S32BIEEELE S32BIEEEBE
+S32BULE S32BUBE
+
diff --git a/machines/mark/machine.h b/machines/mark/machine.h
new file mode 100644
index 0000000..013e6ea
--- /dev/null
+++ b/machines/mark/machine.h
@@ -0,0 +1,93 @@
+#include "dt.h"
+
+//bez speciálních adresních modu
+struct AddressingMode {
+ int never_used;
+};
+
+struct reg_handle {
+ int gpr;
+};
+
+// sem nacpat počet registrů, ale co SP, PC a Zero reg? To jsou spec. registry
+// které kompilátor nemůže jen tak používat
+#define MAXR 16
+
+// počet argumentů, nemám žádné ale doku tvrdí že t i tak musí být MAXGF 1
+#define MAXGF 1
+
+//může být druhý operand IC stejný jako cíl? 0-ano 1-ne
+#define USEQ2ASZ 0
+
+//A co mám jako kurva dát sem?! Zkusím CHAR když to nebude fungovat dej tam INT!
+#define MINADDI2P CHAR
+
+// další wtf! Moje arch tohle neřeší, tak tam prostě prskneme malého indiána
+#define BIGENDIAN 0
+#define LITTLEENDIAN 1
+
+//switche chci compilovat na COMPARE/BEQ nikoliv na SUB/TEST/BEQ
+#define SWITCHSUBS 0
+
+// obšlehnuto z generic, tady toho je vůbec hodně obšlehnutého
+#define INLINEMEMCPY 1024
+
+// reverse argument push order
+//#define ORDERED_PUSH 0
+
+// argumenty klidně do registrů
+#define HAVE_REGPARMS 1
+
+//nemám registrové páry
+#undef HAVE_REGPAIRS
+
+//nó, ale zvhledem k tomu že long a int je na mej arch stejný tak je to asi k prdu ale budiž
+#undef HAVE_INT_SIZET
+
+// a teď ty sračky pro peephole optimalizace, ty dělat nebudu tak jsem tohle obšlehl z generic
+
+/* size of buffer for asm-output, this can be used to do
+ peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+/* We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+
+// tohle je zatím k hovnu později se to ale může hodit
+#define HAVE_TARGET_ATTRIBUTES
+#define HAVE_TARGET_PRAGMAS
+
+#undef HAVE_REGS_MODIFIED //nepodporuji interprocedural register allocation
+
+//tohle je dobrý pro CPU s registrama co mají pevně danou funkci, moje arch je ortogonální až běda tak to nemusím řešit
+#undef HAVE_TARGET_RALLOC
+
+// pro mě zbytečné, je to pro aptimalizaci
+#undef HAVE_EXT_IC
+
+//tohle je sranda, doku se tu odkazuje na kapitolu která není napsaná, nicméně, externí typy nepotřebujeme
+#undef HAVE_EXT_TYPES
+
+#undef HAVE_TGT_PRINTVAL //tohle je stejná sračka jako ta vejš, kdo ví k čemu to je ale nechci to
+
+// no, nemám páru jak to nastavit tak je to obšlehnuté
+#define JUMP_TABLE_DENSITY 0.8
+#define JUMP_TABLE_LENGTH 12
+
+/* toto je pro variable lenght arrays (nutno použít -c99) zatím to jebu, spousta architektur to taky nemá
+#define ALLOCVLA_REG <reg>
+#define ALLOCVLA_INLINEASM <inline asm>
+#define FREEVLA_REG <reg>
+#define FREEVLA_INLINEASM <inline asm>
+#define OLDSPVLA_INLINEASM <inline asm>
+#define FPVLA_REG <reg>
+*/
+
+//tohle je pro nahrazení složitějších operací voláím do knihoven - super věc ale zatím to jebu a budu generovat makra
+#undef HAVE_LIBCALLS
+
+// who cares?
+#define AVOID_FLOAT_TO_UNSIGNED 1
+#define AVOID_UNSIGNED_TO_FLOAT 1
diff --git a/machines/messiahtron/machine.c b/machines/messiahtron/machine.c
new file mode 100755
index 0000000..675df3f
--- /dev/null
+++ b/machines/messiahtron/machine.c
@@ -0,0 +1,2717 @@
+/* Example backend for vbcc, it models a generic 32bit RISC or CISC
+CPU.
+
+Configurable at build-time are:
+- number of (32bit) general-purpose-registers
+- number of (64bit) floating-point-registers
+- number of (8bit) condition-code-registers
+- mechanism for stack-arguments (moving ot fixed sp)
+
+It allows to select as run-time-options:
+- two- or three-address code
+- memory operands or load-store-architecture
+- number of register-arguments
+- number of caller-save-registers
+*/
+
+#include "../../supp.h"
+
+static char FILE_[]=__FILE__;
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc Messiahtron code-generator "__DATE__" (c) in 2008 by Andrew Price";
+
+/* Commandline-flags the code-generator accepts:
+0: just a flag
+VALFLAG: a value must be specified
+STRINGFLAG: a string can be specified
+FUNCFLAG: a function will be called
+apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]={0,0,
+VALFLAG,VALFLAG,VALFLAG,
+0,0,
+VALFLAG,VALFLAG,0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+they collide with the frontend */
+char *g_flags_name[MAXGF]={"three-addr","load-store",
+"volatile-gprs","volatile-fprs","volatile-ccrs",
+"imm-ind","gpr-ind",
+"gpr-args","fpr-args","use-commons"};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. will be initialized in init_cg(),
+register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+estimated cost-saving can be obtained by several registers, the
+one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__interrupt",0};
+
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+#define THREE_ADDR (g_flags[0]&USEDFLAG)
+#define LOAD_STORE (g_flags[1]&USEDFLAG)
+//#define VOL_FIXED NUM_FIXED
+#define VOL_16BIT ((g_flags[3]&USEDFLAG)?g_flags_val[3].l:NUM_16BIT/2)
+#define VOL_32BIT ((g_flags[4]&USEDFLAG)?g_flags_val[4].l:NUM_32BIT/2)
+#define VOL_64BIT ((g_flags[4]&USEDFLAG)?g_flags_val[5].l:NUM_64BIT/2)
+#define VOL_8BIT ((g_flags[4]&USEDFLAG)?g_flags_val[6].l:NUM_8BIT/2)
+#define IMM_IND ((g_flags[5]&USEDFLAG)?1:0)
+#define GPR_IND ((g_flags[6]&USEDFLAG)?2:0)
+//#define ARGS8 ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:1)
+//#define ARGS16 ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:0)
+//#define ARGS32 ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:0)
+//#define ARGS64 ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:0)
+// #define FPR_ARGS ((g_flags[8]&USEDFLAG)?g_flags_val[8].l:0)
+//#define USE_COMMONS (g_flags[9]&USEDFLAG)
+
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={0,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
+
+/* used to initialize regtyp[] */
+static struct Typ llong={LLONG},ltyp={LONG},lshort={SHORT},lchar={CHAR};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+"__GENERIC__",
+0};
+
+/* special registers */
+static int sp; /* Stackpointer */
+static int t8bit1,t8bit2; /* temporary gprs */
+static int t16bit1,t16bit2;
+static int t32bit1,t32bit2;
+static int t64bit1,t64bit2;
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename=".resetlocals\n;code\n",
+*dataname=";data\n",
+*bssname=";bss\n",
+*rodataname=";read only data\n";
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+/* variables to keep track of the current stack-offset in the case of
+a moving stack-pointer */
+static long loff,stackoffset,notpopped,dontpop,maxpushed,stack;
+static pushorder=2;
+
+static long localsize,rsavesize,argsize;
+
+/* pushed on the stack by a callee, no pop needed */
+static void callee_push(long l)
+{
+}
+
+static void push(long l)
+{
+ stackoffset-=l;
+ if(stackoffset<maxpushed)
+ maxpushed=stackoffset;
+}
+static void pop(long l)
+{
+ stackoffset+=l;
+}
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+stack-pointer; we use a layout like this:
+------------------------------------------------
+| arguments to this function |
+------------------------------------------------
+| return-address [size=4] |
+------------------------------------------------
+| caller-save registers [size=rsavesize] |
+------------------------------------------------
+| local variables [size=localsize] |
+------------------------------------------------
+| arguments to called functions [size=argsize] |
+------------------------------------------------
+All sizes will be aligned as necessary.
+In the case of FIXED_SP, the stack-pointer will be adjusted at
+function-entry to leave enough space for the arguments and have it
+aligned to 16 bytes. Therefore, when calling a function, the
+stack-pointer is always aligned to 16 bytes.
+For a moving stack-pointer, the stack-pointer will usually point
+to the bottom of the area for local variables, but will move while
+arguments are put on the stack.
+
+This is just an example layout. Other layouts are also possible.
+*/
+
+static long real_offset(struct obj *o)
+{
+ long off=zm2l(o->v->offset);
+ if(off<0){
+ /* function parameter */
+ off=localsize+rsavesize+4-off-zm2l(maxalign);
+ }
+
+ off+=4;
+
+ off+=stackoffset;
+ off+=zm2l(o->val.vmax);
+ return off;
+}
+
+/* Initializes an addressing-mode structure and returns a pointer to
+that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ am.offset=offset;
+ return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+ char *sec;
+ if(!v->vattr) return 0;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return 0;
+ sec+=strlen("section(");
+ emit(f,"; section");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/* Generates code to load the address of a variable into register r. */
+{
+ if(!(o->flags&VAR))
+ ierror(0);
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)
+ {
+ long off=real_offset(o);
+ emit(f,"\tmov\t%s %s ; load_address %s\n",regnames[r],regnames[sp],dt(POINTER));
+ if(off)
+ {
+ emit(f,"\tmov\tb30 %ld ; %s\n",off,dt(POINTER));
+ emit(f,"\tsub\t%s b30 ; %s\n",regnames[r],dt(POINTER));
+ }
+ }
+ else
+ {
+ emit(f,"\tmov\t%s ",regnames[r]);
+ emit_obj(f,o,type);
+ emit(f," ;%s\n", dt(POINTER));
+ }
+}
+/* Generates code to load a memory object into register r. tmp is a
+general purpose register which may be used. tmp can be r. */
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+ type&=NU;
+ if(o->flags&VARADR)
+ {
+ load_address(f,r,o,POINTER);
+ }
+ else
+ {
+ if((o->flags&(REG|DREFOBJ))==REG&&o->reg==r)
+ return;
+ if((o->flags&VAR)&&!(o->flags®))
+ {
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)
+ {
+ unsigned long offset = real_offset(o);
+ if(offset == 0)
+ {
+ emit(f,"\tmov\t%s\t[z2] ;%s\n",regnames[r],dt(type));
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ if(ISFLOAT(type))
+ emit(f,"\tmovf\t%s\t[b29] ;%s\n",regnames[r],dt(type));
+ else if((type & UNSIGNED) || type == POINTER || type == STRUCT)
+ emit(f,"\tmov\t%s\t[b29] ;%s\n",regnames[r],dt(type));
+ else
+ emit(f,"\tmovs\t%s\t[b29] ;%s\n",regnames[r],dt(type));
+ }
+
+ return;
+ }
+ }
+
+ if(ISFLOAT(type))
+ emit(f,"\tmovf \t%s ",regnames[r]);
+ else if((type & UNSIGNED) || type == POINTER || type == STRUCT)
+ emit(f,"\tmov \t%s ",regnames[r]);
+ else
+ emit(f,"\tmovs \t%s ",regnames[r]);
+ emit_obj(f,o,type);
+ emit(f," ;%s\n",dt(type));
+ }
+}
+
+/* Generates code to store register r into memory object o. */
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+ type&=NQ;
+
+ if((o->flags&VAR)&&!(o->flags®))
+ {
+
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)
+ {
+ unsigned long offset = real_offset(o);
+
+ if(offset == 0)
+ {
+ if(ISFLOAT(type))
+ emit(f,"\tmovf\t[z2]\t%s ;%s\n",regnames[r],dt(type));
+ else if((type & UNSIGNED) || type == POINTER || type == STRUCT)
+ emit(f,"\tmov\t[z2]\t%s ;%s\n",regnames[r],dt(type));
+ else
+ emit(f,"\tmovs\t[z2]\t%s ;%s\n",regnames[r],dt(type));
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; mov to stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ if(ISFLOAT(type))
+ emit(f,"\tmovf\t[b29]\t%s ;%s\n",regnames[r],dt(type));
+ else if((type & UNSIGNED) || type == POINTER || type == STRUCT)
+ emit(f,"\tmov\t[b29]\t%s ;%s\n",regnames[r],dt(type));
+ else
+ emit(f,"\tmovs\t[b29]\t%s ;%s\n",regnames[r],dt(type));
+ }
+ return;
+ }
+ }
+ if(r == 0)
+ emit(f, ";");
+
+ if(ISFLOAT(type))
+ emit(f,"\tmovf\t");
+ else if(type & UNSIGNED)
+ emit(f,"\tmov\t");
+ else
+ emit(f,"\tmovs\t");
+
+ emit_obj(f,o,type);
+ emit(f,"\t%s ;%s\n",regnames[r],dt(type));
+}
+
+/* Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+
+static struct IC *preload(FILE *,struct IC *);
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static int q1reg,q2reg,zreg;
+
+/* Does some pre-processing like fetching operands from memory to
+registers etc. */
+static struct IC *preload(FILE *f,struct IC *p)
+{
+ int r;
+
+ if(isreg(q1))
+ q1reg=p->q1.reg;
+ else
+ q1reg=0;
+
+ if(isreg(q2))
+ q2reg=p->q2.reg;
+ else
+ q2reg=0;
+
+// emit(f," ; Preload register type %d\t%d z:%d\t%d\t ", q1typ(p), q1typ(p) & NQ, ztyp(p), ztyp(p) & NQ);
+
+ if(isreg(z))
+ {
+ zreg=p->z.reg;
+// emit(f," is a reg ");
+ }
+ else
+ {
+ if((ztyp(p) & NQ) == CHAR)
+ {
+// emit(f," is a 8 bit reg (1) ");
+ zreg=t8bit1;
+ }
+ else if((ztyp(p) & NQ) == SHORT)
+ {
+// emit(f," is a 16 bit reg (1) ");
+ zreg=t16bit1;
+ }
+ else if((ztyp(p) & NQ) == LDOUBLE || (ztyp(p) & NQ) == LLONG || (ztyp(p) & NQ) == DOUBLE)
+ {
+// emit(f," is a 64 bit reg (1) ");
+ zreg=t64bit1;
+ }
+ else
+ {
+// emit(f," is a 32 bit reg (1) ");
+ zreg=t32bit1;
+ }
+ }
+
+ if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am){
+ p->q1.flags&=~DREFOBJ;
+ if((q1typ(p) & NQ) == CHAR)
+ {
+ load_reg(f,t8bit1,&p->q1,q1typ(p));
+ p->q1.reg=t8bit1;
+// emit(f," is a 8 bit reg (2) ");
+ }
+ else if((q1typ(p) & NQ) == SHORT)
+ {
+ load_reg(f,t16bit1,&p->q1,q1typ(p));
+ p->q1.reg=t16bit1;
+// emit(f," is a 16 bit reg (2) ");
+ }
+ else if((q1typ(p) & NQ) == LDOUBLE || (q1typ(p) & NQ) == LLONG || (q1typ(p) & NQ) == DOUBLE)
+ {
+ load_reg(f,t64bit1,&p->q1,q1typ(p));
+ p->q1.reg=t64bit1;
+// emit(f," is a 64 bit reg (2) ");
+ }
+ else
+ {
+ load_reg(f,t32bit1,&p->q1,q1typ(p));
+ p->q1.reg=t32bit1;
+// emit(f," is a 32 bit reg (2) ");
+ }
+ p->q1.flags|=(REG|DREFOBJ);
+ }
+ if(p->q1.flags&&LOAD_STORE&&!isreg(q1)){
+ if((q1typ(p) & NQ) == CHAR)
+ {
+ q1reg=t8bit1;
+// emit(f," is a 8 bit reg (3) ");
+ }
+ else if((q1typ(p) & NQ) == SHORT)
+ {
+ q1reg=t16bit1;
+// emit(f," is a 16 bit reg (3) ");
+ }
+ else if((q1typ(p) & NQ) == LDOUBLE || (q1typ(p) & NQ) == LLONG || (q1typ(p) & NQ) == DOUBLE)
+ {
+ q1reg=t64bit1;
+// emit(f," is a 64 bit reg (3) ");
+ }
+ else
+ {
+ q1reg=t32bit1;
+// emit(f," is a 32 bit reg (3) ");
+ }
+ load_reg(f,q1reg,&p->q1,q1typ(p));
+ p->q1.reg=q1reg;
+ p->q1.flags=REG;
+ }
+
+ if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am){
+ p->q2.flags&=~DREFOBJ;
+ if((q1typ(p) & NQ) == CHAR)
+ {
+ load_reg(f,t8bit1,&p->q2,q2typ(p));
+ p->q2.reg=t8bit1;
+// emit(f," is a 8 bit reg (4) ");
+ }
+ else if((q1typ(p) & NQ) == SHORT)
+ {
+ load_reg(f,t16bit1,&p->q2,q2typ(p));
+ p->q2.reg=t16bit1;
+// emit(f," is a 16 bit reg (4) ");
+ }
+ else if((q1typ(p) & NQ) == LDOUBLE || (q1typ(p) & NQ) == LLONG || (q1typ(p) & NQ) == DOUBLE)
+ {
+ load_reg(f,t64bit1,&p->q2,q2typ(p));
+ p->q2.reg=t64bit1;
+// emit(f," is a 64 bit reg (4) ");
+ }
+ else
+ {
+ load_reg(f,t32bit1,&p->q2,q2typ(p));
+ p->q2.reg=t32bit1;
+// emit(f," is a 32 bit reg (4) ");
+ }
+
+ p->q2.flags|=(REG|DREFOBJ);
+ }
+ if(p->q2.flags&&LOAD_STORE&&!isreg(q2)){
+ if((q1typ(p) & NQ) == CHAR)
+ {
+ q2reg=t8bit1;
+// emit(f," is a 8 bit reg (5) ");
+ }
+ else if((q1typ(p) & NQ) == SHORT)
+ {
+ q2reg=t16bit1;
+// emit(f," is a 16 bit reg (5) ");
+ }
+ else if((q1typ(p) & NQ) == LDOUBLE || (q1typ(p) & NQ) == LLONG || (q1typ(p) & NQ) == DOUBLE)
+ {
+ q2reg=t64bit1;
+// emit(f," is a 64 bit reg (5) ");
+ }
+ else
+ {
+ q2reg=t32bit1;
+// emit(f," is a 32 bit reg (5) ");
+ }
+
+ load_reg(f,q2reg,&p->q2,q2typ(p));
+ p->q2.reg=q2reg;
+ p->q2.flags=REG;
+ }
+
+// emit(f,"\n");
+ return p;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+ if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
+ p->z.flags&=~DREFOBJ;
+ if((p->typf & NQ) == CHAR)
+ {
+ load_reg(f,t8bit2,&p->z,POINTER);
+ p->z.reg=t8bit2;
+ }
+ else if((p->typf & NQ) == SHORT)
+ {
+ load_reg(f,t16bit2,&p->z,POINTER);
+ p->z.reg=t16bit2;
+ }
+ else if((p->typf & NQ) == LDOUBLE || (p->typf & NQ) == LLONG || (p->typf & NQ) == DOUBLE)
+ {
+ load_reg(f,t64bit2,&p->z,POINTER);
+ p->z.reg=t64bit2;
+ }
+ else
+ {
+ load_reg(f,t32bit2,&p->z,POINTER);
+ p->z.reg=t32bit2;
+ }
+ p->z.flags|=(REG|DREFOBJ);
+ //printf("setting reg to %s\n", regnames[p->z.reg]);
+ }
+
+ if(isreg(z)){
+ if(p->z.reg!=zreg)
+ emit(f,"\tmov\t%s %s ;%s\n",regnames[p->z.reg],regnames[zreg],dt(ztyp(p)));
+ }else{
+ store_reg(f,zreg,&p->z,ztyp(p));
+ }
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+ //printf("type = %i\n", t);
+ if((p->flags&(DREFOBJ|KONST))==(DREFOBJ|KONST))
+ {
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG))
+ emit(f,"[");
+
+ if((p->flags&VAR)&&!(p->flags®))
+ {
+ if(!zmeqto(l2zm(0L),p->val.vmax))
+ {
+ emitval(f,&p->val,LONG);
+ emit(f,"+");
+ }
+ if(p->v->storage_class==STATIC)
+ {
+ emit(f,"%s%ld", labprefix, zm2l(p->v->offset));
+ }
+ else
+ {
+ if(t == FUNKT)
+ emit(f,"%s%s", idprefix, p->v->identifier);
+ else if(p->flags&VARADR)
+ emit(f,"%s%s", idprefix, p->v->identifier);
+ else
+ emit(f,"[%s%s]", idprefix, p->v->identifier);
+ }
+ }
+ if(p->flags®)
+ {
+ emit(f, "%s", regnames[p->reg]);
+ }
+ if(p->flags&KONST)
+ {
+ if(ISFLOAT(t))
+ {
+ // case FLOAT:
+ char *values = (char *)&p->val.vfloat;
+ // swap the order
+ char tmp = values[0];
+ values[0] = values[3];
+ values[3] = tmp;
+ tmp = values[1];
+ values[1] = values[2];
+ values[2] = tmp;
+
+ emit(f, "0x%1X", *(unsigned int *)values);
+ // break;
+
+ // case DOUBLE:
+ // fprintf(fp, "[double #%08X]", obj->val.vdouble);
+ // emit(f,"0f%e",/*labprefix,*/p->val.vfloat);
+ // emit(f,"0f");
+ // emitval(f,&p->val,t&NU);
+ }
+ else if(t & UNSIGNED)
+ {
+ // emit(f, "0u");
+ emitval(f,&p->val,t&NU);
+ }
+ else
+ {
+ emit(f,"0s");
+ emitval(f,&p->val,t&NU);
+ }
+ }
+ if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG))
+ emit(f,"]");
+}
+
+/* Test if there is a sequence of FREEREGs containing FREEREG reg.
+Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+ while(p&&(p->code==FREEREG||p->code==ALLOCREG))
+ {
+ if(p->code==FREEREG&&p->q1.reg==reg)
+ return 1;
+ p=p->next;
+ }
+ return 0;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+ int c,c2,r;
+ struct IC *p2;
+ struct AddressingMode *am;
+
+ for(;p;p=p->next)
+ {
+ c=p->code;
+ if(c != FREEREG && c != ALLOCREG && (c != SETRETURN || !isreg(q1) || p->q1.reg != p->z.reg))
+ exit_label=0;
+ if(c==LABEL)
+ exit_label=p->typf;
+
+ /* Try const(reg) */
+ if(IMM_IND&&(c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST)
+ {
+ int base;zmax of;struct obj *o;
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ if(1/*zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))*/)
+ {
+ r=p->z.reg;
+ if(isreg(q1))
+ base=p->q1.reg;
+ else
+ base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next)
+ {
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA))
+ break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r)
+ break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r)
+ break;
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/)
+ {
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r)
+ {
+ if(o) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r)
+ {
+ if(o) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r)
+ {
+ if(o) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG)
+ {
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r)
+ {
+ if(o)
+ {
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ am->base=base;
+ am->offset=zm2l(of);
+ if(isreg(q1))
+ {
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }
+ else
+ {
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base)
+ break;
+ continue;
+ }
+ }
+ }
+ }
+ /* Try reg,reg */
+ if(GPR_IND&&c==ADDI2P&&isreg(q2)&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg))
+ {
+ int base,idx;struct obj *o;
+ r=p->z.reg;idx=p->q2.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next)
+ {
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA))
+ break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r)
+ break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r)
+ break;
+ if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r)
+ break;
+
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/)
+ {
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r)
+ {
+ if(o||(q1typ(p2)&NQ)==LLONG) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r)
+ {
+ if(o||(q2typ(p2)&NQ)==LLONG) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r)
+ {
+ if(o||(ztyp(p2)&NQ)==LLONG) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG)
+ {
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r)
+ {
+ if(o)
+ {
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=GPR_IND;
+ am->base=base;
+ am->offset=idx;
+ if(isreg(q1))
+ {
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }
+ else
+ {
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+}
+
+static void pr(FILE *f,struct IC *p)
+{
+ int i;
+ for(;pushorder>2;pushorder>>=1)
+ {
+ for(i=1;i<=8;i++)
+ {
+ if(regs[i]&pushorder)
+ {
+ if(p->code==PUSH||p->code==CALL)
+ {
+ //emit(f,"\tmovl\t%ld(%s),%s\n",loff-4-stackoffset,regnames[sp],regnames[i]);
+ }
+ else
+ {
+ emit(f,"\tpop\t%s\n",regnames[i]);
+ pop(4);
+ }
+ regs[i]&=~pushorder;
+ }
+ }
+ }
+ for(i=1;i<=8;i++)
+ if(regs[i]&2) regs[i]&=~2;
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+ rsavesize=0;
+ if(!special_section(f,v)&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(v->storage_class==EXTERN)
+ {
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,".global ");
+ // emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }
+ else
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+
+ // reserve enough in stack for local functions
+ if(offset > 0)
+ {
+ emit(f,"\tmov\tb28\t%d\n", offset);
+ emit(f,"\tadd\tz2\tb28 ;reserve %d on stack\n", offset);
+ }
+}
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+ // reserve enough in stack for local functions
+ if(offset > 0)
+ {
+ emit(f,"\tmov\tb28\t%d\n", offset);
+ emit(f,"\tsub\tz2\tb28 ;reserve %d on stack\n", offset);
+ }
+
+ emit(f,ret);
+}
+
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+int init_cg(void)
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(1L);
+ char_bit=l2zm(8L);
+
+ for(i=0;i<=MAX_TYPE;i++)
+ {
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+
+ regnames[0]="noreg";
+ regtype[0]=mymalloc(sizeof(struct Typ));
+ // for(i=FIRST_FIXED;i<=LAST_FIXED;i++)
+ // {
+ // regnames[i]=mymalloc(10);
+ // sprintf(regnames[i],"b%d",(i-FIRST_FIXED) + 27);
+ // regsize[i]=4;
+ // regtype[i]=<yp;
+ // }
+
+ // static struct Typ lltype={LLONG},ltyp={LONG},lshort={SHORT},lchar={CHAR};
+
+ for(i=FIRST_16BIT;i<=LAST_16BIT;i++)
+ {
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"a%d",i-FIRST_16BIT);
+ regsize[i]=2;
+ regtype[i]=mymalloc(sizeof(struct Typ));
+ }
+
+ for(i=FIRST_32BIT;i<=LAST_32BIT;i++)
+ {
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"b%d",(i-FIRST_32BIT) + 5);
+ regsize[i]=4;
+ regtype[i]=mymalloc(sizeof(struct Typ));
+ }
+
+ for(i=FIRST_64BIT;i<=LAST_64BIT;i++)
+ {
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"c%d",(i-FIRST_64BIT) + 9);
+ regsize[i]=8;
+ regtype[i]=mymalloc(sizeof(struct Typ));
+ }
+
+ for(i=FIRST_8BIT;i<=LAST_8BIT;i++)
+ {
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"h%d",(i-FIRST_8BIT));
+ regsize[i]=1;
+ //regtype[i]=&lchar;
+ regtype[i]=mymalloc(sizeof(struct Typ));
+ }
+
+ regnames[STACK_POINTER]=mymalloc(10);
+ sprintf(regnames[STACK_POINTER],"z2");
+ regsize[STACK_POINTER]=4;
+ regtype[STACK_POINTER]=<yp;
+ regtype[STACK_POINTER]=mymalloc(sizeof(struct Typ));
+
+ /* Use multiple ccs. */
+ multiple_ccs=0;
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LONG]=t_min(INT);
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=ul2zum(2147483647UL);
+ t_max[LONG]=t_max(INT);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=ul2zum(4294967295UL);
+ tu_max[LONG]=t_max(UNSIGNED|INT);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ for(i=FIRST_16BIT;i<=LAST_16BIT-VOL_16BIT;i++)
+ regscratch[i]=1;
+ for(i=FIRST_32BIT;i<=LAST_32BIT-VOL_32BIT;i++)
+ regscratch[i]=1;
+ for(i=FIRST_64BIT;i<=LAST_64BIT-VOL_64BIT;i++)
+ regscratch[i]=1;
+ for(i=FIRST_8BIT;i<=LAST_8BIT-VOL_8BIT;i++)
+ regscratch[i]=1;
+
+ /* Reserve a few registers for use by the code-generator. */
+ /* This is not optimal but simple. */
+ sp=STACK_POINTER;
+ t8bit1=FIRST_8BIT;
+ t8bit2=FIRST_8BIT+1;
+ t16bit1=FIRST_16BIT;
+ t16bit2=FIRST_16BIT+1;
+ t32bit1=FIRST_32BIT;
+ t32bit2=FIRST_32BIT+1;
+ t64bit1=FIRST_64BIT;
+ t64bit2=FIRST_64BIT+1;
+ regsa[t8bit1]=regsa[t8bit2]=1;
+ regsa[t16bit1]=regsa[t16bit2]=1;
+ regsa[t32bit1]=regsa[t32bit2]=1;
+ regsa[t64bit1]=regsa[t64bit2]=1;
+ regsa[sp]=1;
+ regscratch[t8bit1]=regscratch[t8bit2]=0;
+ regscratch[t16bit1]=regscratch[t16bit2]=0;
+ regscratch[t32bit1]=regscratch[t32bit2]=0;
+ regscratch[t64bit1]=regscratch[t64bit2]=0;
+ regscratch[sp]=0;
+
+ // for(i=FIRST_FIXED;i<=LAST_FIXED-VOL_FIXED;i++)
+ // regscratch[i]=1;
+ target_macros=marray;
+
+ return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+/* A pointer MUST be returned in a register. The code-generator */
+/* has to simulate a pseudo register if necessary. */
+{
+ if(ISSTRUCT(t->flags)||ISUNION(t->flags))
+ return 0;
+ if(t->size == 1)
+ return FIRST_8BIT+3;
+ if(t->size == 2)
+ return FIRST_16BIT+3;
+ if(t->size == 4)
+ return FIRST_32BIT+3;
+ if(t->size == 8)
+ return FIRST_64BIT+3;
+
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+ int c=p->code;
+ if(o->flags&VKONST)
+ {
+ if(!LOAD_STORE)
+ return 0;
+ if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
+ return 4;
+ else
+ return 2;
+ }
+ if(o->flags&DREFOBJ)
+ return 4;
+ if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ))
+ return 3;
+ if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ))
+ return 3;
+ return 2;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(r==0)
+ return 0;
+ t&=NQ;
+
+ if(r>=FIRST_8BIT&&r<=LAST_8BIT)
+ {
+// printf("8 bit register: ");
+ if(t == CHAR)
+ {
+// printf(" can fit\n");
+ return 1;
+ }
+// else
+// printf(" can't fit\n");
+ }
+ else if(r>=FIRST_16BIT&&r<=LAST_16BIT)
+ {
+// printf("16 bit register: ");
+ if(t == SHORT)
+ {
+// printf(" can fit\n");
+ return 1;
+ }
+// else
+// printf(" can't fit\n");
+ }
+ else if(r>=FIRST_32BIT&&r<=LAST_32BIT)
+ {
+// printf("32 bit register: ");
+ if(t == INT || t == LONG || t == FLOAT
+ ||t == POINTER)
+ {
+// printf(" can fit\n");
+ return 1;
+ }
+// etse
+// printf(" can't fit\n");
+ }
+ else if(r>=FIRST_64BIT&&r<=LAST_64BIT)
+ {
+// printf("64 bit register: ");
+ if(t == LDOUBLE || t == DOUBLE || t == LLONG)
+ {
+// printf(" can fit\n");
+ return 1;
+ }
+// else
+// printf(" can't fit\n");;
+ }
+
+ return 0;
+
+
+ /*#define CHAR 1
+ #define SHORT 2
+ #define INT 3
+ #define LONG 4
+ #define LLONG 5
+ #define FLOAT 6
+ #define DOUBLE 7
+ #define LDOUBLE 8
+ #define VOID 9
+ #define POINTER 10
+ #define ARRAY 11
+ #define STRUCT 12
+ #define UNION 13
+ #define ENUM 14*/
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* On the PowerPC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op=o&NQ,tp=t&NQ;
+
+ if(op == LONG || op == POINTER)
+ op = INT;
+
+ if(tp==LONG || tp ==POINTER)
+ tp = INT;
+
+ if(op == tp) // same type
+ if((o & NQ)== (t & NQ)) // same signess
+ return 0; // no code needed
+
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ if(newobj&§ion!=SPECIAL)
+ emit(f," data %ld\n",zm2l(size));
+ else
+ emit(f," data %ld\n",zm2l(size));
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ if(zm2l(align)>1)
+ emit(f,"; NOT IMPLEMENTED - \t.align\t%d\n", align);
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;
+ char *sec;
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC)
+ {
+ if(ISFUNC(v->vtyp->flags))
+ return;
+ if(!special_section(f,v))
+ {
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(v->clist||section==SPECIAL)
+ {
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }
+ else
+ emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+ newobj=1;
+ }
+ if(v->storage_class==EXTERN)
+ {
+ // emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+ if(v->flags&(DEFINED|TENTATIVE))
+ {
+ if(!special_section(f,v))
+ {
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA)
+ {
+ emit(f,dataname);
+ if(f)
+ section=DATA;
+ }
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA)
+ {
+ emit(f,rodataname);
+ if(f)
+ section=RODATA;
+ }
+ if(!v->clist&§ion!=BSS)
+ {
+ emit(f,bssname);
+ if(f)
+ section=BSS;
+ }
+ }
+ if(v->clist||section==SPECIAL)
+ {
+ gen_align(f,falign(v->vtyp));
+ // emit(f,"%s%s:\n",idprefix,v->identifier);
+ }
+ else
+ emit(f,".global %s%s:",/*(USE_COMMONS?"":"l"),*/idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ //emit(f,"\tdc.%s\t",dt(t&NQ));
+ int o = t&NQ;
+ int size = 4;
+ if(o == CHAR)
+ size = 1;
+ if(o == SHORT)
+ size = 2;
+ if(o == LLONG || t == DOUBLE)
+ size = 8;
+
+ emit(f,"\tdata\t%i\t",size);
+ if(!p->tree)
+ {
+ if(ISFLOAT(t))
+ {
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ if((t&NQ)!=FLOAT){
+ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ }
+ else if(o & UNSIGNED)
+ {
+ emitval(f,&p->val,t);
+ }
+ else
+ {
+ emit(f, "0s");
+ emitval(f,&p->val,t);
+ }
+ }
+ else
+ {
+ emit_obj(f,&p->tree->o,t);
+ }
+ emit(f,"\n");
+ newobj=0;
+}
+
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/* The main code-generation. */
+{
+ int c,t,i,lastcomp=0;
+ struct IC *m;
+ argsize=0;
+ if(DEBUG&1)
+ printf("gen_code()\n");
+ for(c=1;c<=MAXR;c++)
+ regs[c]=regsa[c];
+ maxpushed=0;
+
+ /*FIXME*/
+ ret="\tret\n";
+
+ struct IC *p_test = 0;
+ char test_handled = 0;
+ int test_reg = 0;
+ int test_reg2 = 0;
+
+ for(m=p;m;m=m->next)
+ {
+ c=m->code;t=m->typf;
+ if(c==ALLOCREG)
+ {
+ regs[m->q1.reg]=1;
+ continue;
+ }
+ if(c==FREEREG)
+ {
+ regs[m->q1.reg]=0;
+ continue;
+ }
+
+ /* convert MULT/DIV/MOD with powers of two */
+ if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED))))
+ {
+ eval_const(&m->q2.val,t);
+ i=pof2(vmax);
+ if(i)
+ {
+ if(c==MOD)
+ {
+ vmax=zmsub(vmax,l2zm(1L));
+ m->code=AND;
+ }
+ else
+ {
+ vmax=l2zm(i-1);
+ if(c==DIV)
+ m->code=RSHIFT;
+ else
+ m->code=LSHIFT;
+ }
+ c=m->code;
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ if(c==AND)
+ {
+ insert_const(&m->q2.val,t);
+ }
+ else
+ {
+ insert_const(&m->q2.val,INT);
+ p->typf2=INT;
+ }
+ }
+ }
+#if FIXED_SP
+ if(c==CALL&&argsize<zm2l(m->q2.val.vmax))
+ argsize=zm2l(m->q2.val.vmax);
+#endif
+ }
+ peephole(p);
+
+ for(c=1;c<=MAXR;c++)
+ {
+ if(regsa[c]||regused[c])
+ {
+ BSET(regs_modified,c);
+ }
+ }
+
+ localsize=(zm2l(offset)+3)/4*4;
+#if FIXED_SP
+ /*FIXME: adjust localsize to get an aligned stack-frame */
+#endif
+
+ function_top(f,v,localsize);
+
+ stackoffset=notpopped=dontpop=0;
+
+ for(;p;p=p->next)
+ {
+ c=p->code;t=p->typf;
+ if(c==NOP)
+ {
+ p->z.flags=0;
+ continue;
+ }
+
+ if(c==ALLOCREG)
+ {
+ regs[p->q1.reg]=1;
+ continue;
+ }
+
+ if(c==FREEREG)
+ {
+ regs[p->q1.reg]=0;
+ continue;
+ }
+ if(c==LABEL)
+ {
+ emit(f,"%s%d:\n",labprefix,t);
+ continue;
+ }
+
+ if(notpopped&&!dontpop)
+ {
+ if(c==LABEL||c==COMPARE||c==TEST||c==BRA)
+ {
+ emit(f,"\taddl\t$%ld,%%esp\n",notpopped);
+ pop(notpopped);
+ notpopped=0;
+ }
+ }
+ if(c==BRA)
+ {
+ emit(f,"\tmov b29 %s%d\n", labprefix, t);
+ emit(f,"\tjmp\tb29\n");
+
+ //emit(f,"\tmov b29\t");
+ //if(isreg(q1)){
+ //emit_obj(f,&p->q1,0);
+ //emit(f,",");
+ //}
+ //emit(f,"%s%d;\n",labprefix,t);
+ continue;
+ }
+
+ if(c==MOVETOREG)
+ {
+ //printf("reg: %s\n", regnames[p->z.reg]);
+ if(p->z.reg <= MAXR)
+ load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+ else
+ emit(f," ; move non existant reg in to %s\n",regnames[p->q1.reg]);
+ continue;
+ }
+ if(c==MOVEFROMREG)
+ {
+ // printf("reg: %s\n", regnames[p->z.reg]);
+ if(p->z.reg <= MAXR)
+ store_reg(f, p->z.reg, &p->q1, regtype[p->z.reg]->flags);
+ continue;
+ }
+ if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1)))
+ {
+ ierror(0);
+ }
+ p=preload(f,p);
+ c=p->code;
+ if(c==SUBPFP)
+ c=SUB;
+ if(c==ADDI2P)
+ c=ADD;
+ if(c==SUBIFP)
+ c=SUB;
+ if(c==CONVERT)
+ {
+ load_reg(f,zreg,&p->q1,p->typf2);
+ if(ISFLOAT(p->typf)) // convert to float
+ {
+ if(ISFLOAT(p->typf2)) // from float
+ {
+ // emit(f,"\tmovf\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);
+ }
+ else if(!(p->typf2 & UNSIGNED)) // from signed
+ {
+ // emit(f,"\tmovs\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);
+ emit(f,"\tstf\t%s ;%s\n",regnames[zreg],dt(q1typ(p)));
+ }
+ else if(p->typf2 & UNSIGNED) // from unsigned
+ {
+ // emit(f,"\tmov\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);
+ emit(f,"\tutf\t%s ;%s\n",regnames[zreg],dt(q1typ(p)));
+ }
+ }
+ else if(!(p->typf & UNSIGNED)) // convert to signed
+ {
+ if(ISFLOAT(p->typf2)) // from float
+ {
+ // emit(f,"\tmovf\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);
+ emit(f,"\tfts\t%s ;%s\n",regnames[zreg],dt(q1typ(p)));
+ }
+ else if(!(p->typf2 & UNSIGNED)) // from signed
+ {
+ // emit(f,"\tmovs\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);
+ }
+ else if(p->typf2 & UNSIGNED) // from unsigned
+ {
+ // emit(f,"\tmov\t%s\t", regnames[zreg]);
+ // emit_obj(f,&p->q1,p->typf2);
+// emit(f,"\n\tuts\t%s ;%s\n",regnames[zreg],dt(q1typ(p)));
+ }
+ }
+ else if(p->typf & UNSIGNED) // convert to unsigned
+ {
+ if(ISFLOAT(p->typf2)) // from float
+ {
+ // emit(f,"\tmovf\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);
+ emit(f,"\tftu\t%s ;%s\n",regnames[zreg],dt(q1typ(p)));
+ }
+ else if(!(p->typf2 & UNSIGNED)) // from signed
+ {
+ // emit(f,"\tmovs\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);
+// emit(f,"\tstu\t%s ;%s\n",regnames[zreg],dt(q1typ(p)));
+ }
+ else if(p->typf2 & UNSIGNED) // from unsigned
+ {
+ // emit(f,"\tmov\t%s\t%s\n", regnames[zreg], regnames[p->q1.reg]);
+ }
+ }
+ save_result(f,p);
+ continue;
+ }
+ if(c==KOMPLEMENT)
+ {
+ load_reg(f,zreg,&p->q1,t);
+ emit(f,"\tcpl.%s\t%s\n",dt(t),regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c==SETRETURN)
+ {
+ load_reg(f,p->z.reg,&p->q1,t);
+ BSET(regs_modified,p->z.reg);
+ continue;
+ }
+ if(c==GETRETURN)
+ {
+ if(p->q1.reg)
+ {
+ zreg=p->q1.reg;
+ save_result(f,p);
+ }
+ else
+ p->z.flags=0;
+ continue;
+ }
+ if(c==CALL)
+ {
+ int reg;
+ /*FIXME*/
+#if 0
+ if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK))
+ {
+ if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+ stack=framesize+zum2ul(p->q1.v->fi->stack1);
+ }else
+ stack_valid=0;
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm)
+ {
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ }
+ else
+ {
+ emit(f, "\tmov\tb29\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ emit(f,"\tcall\tb29\n");
+ }
+ /*FIXME*/
+#if FIXED_SP
+ pushed-=zm2l(p->q2.val.vmax);
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS))
+ {
+ bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+ }
+ else
+ {
+ int i;
+ for(i=1;i<=MAXR;i++)
+ {
+ if(regscratch[i]) BSET(regs_modified,i);
+ }
+ }
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH)
+ {
+ if(t==0)
+ ierror(0);
+ if(c==PUSH)
+ {
+ emit(f,"\tpush\t"/*,dt(t)*/);
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ push(zm2l(p->q2.val.vmax));
+ continue;
+ }
+ if(c==ASSIGN)
+ {
+ load_reg(f,zreg,&p->q1,t);
+ if(q2reg != 0)
+ load_reg(f,q2reg,&p->q2,t);
+ save_result(f,p);
+ }
+ continue;
+ }
+ if(c==ADDRESS)
+ {
+ load_address(f,zreg,&p->q1,POINTER);
+ save_result(f,p);
+ continue;
+ }
+ if(c==MINUS)
+ {
+ load_reg(f,zreg,&p->q1,t);
+ emit(f,"\tneg\t%s ; %s\n",dt(t),regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c >= BEQ && c < BRA)
+ {
+
+ char *ccu[]={"cmp","nequ","gt","!gte","gte","!gt"};
+ char *ccs[]={"cmps","nequs","gts","!gtes","gtes","!gts"};
+ char *ccf[]={"cmpf","nequf","gtf","!gtef","gtef","!gtf"};
+ if(p_test == 0)
+ {
+ printf("Calling %s without a test!\n",ccs[c-BEQ]);
+ emit(f,"Calling %s without a test!\n",ccs[c-BEQ]);
+ continue;
+ }
+
+ struct IC *p_old = p;
+ p = p_test;
+ t=p->typf;
+
+ if(test_handled == 0)
+ {
+ if(ISFLOAT(t))
+ {
+ if(isreg(q2))
+ {
+ char instruction[10];
+ sprintf(instruction, "%s", ccf[c-BEQ]);
+ if(instruction[0] == '!')
+ {
+ instruction[0] = ' ';
+ emit(f,"\n\t%s\t%s\t%s\n",instruction,regnames[test_reg],regnames[test_reg2]);
+ }
+ else
+ emit(f,"\n\t%s\t%s\t%s\n",instruction,regnames[test_reg2],regnames[test_reg]);
+
+ save_result(f,p);
+ }
+ else
+ {
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmovf\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmovf\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmovf\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ char instruction[10];
+ sprintf(instruction, "%s", ccf[c-BEQ]);
+ if(instruction[0] == '!')
+ {
+ instruction[0] = ' ';
+ emit(f,"\n\t%s\t%s\tb28\n",instruction,regnames[test_reg]);
+ }
+ else
+ emit(f,"\n\t%s\tb28\t%s\n",instruction,regnames[test_reg]);
+ }
+ }
+ else if(t & UNSIGNED)
+ {
+ if(isreg(q2))
+ {
+ char instruction[10];
+ sprintf(instruction, "%s", ccu[c-BEQ]);
+ if(instruction[0] == '!')
+ {
+ instruction[0] = ' ';
+ emit(f,"\n\t%s\t%s\t%s\n",instruction,regnames[test_reg2],regnames[test_reg]);
+ }
+ else
+ emit(f,"\n\t%s\t%s\t%s\n",instruction,regnames[test_reg],regnames[test_reg2]);
+ save_result(f,p);
+ continue;
+ }
+ else
+ {
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmov\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmov\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ char instruction[10];
+ sprintf(instruction, "%s", ccu[c-BEQ]);
+ if(instruction[0] == '!')
+ {
+ instruction[0] = ' ';
+ emit(f,"\n\t%s\t%s\tb28\n",instruction,regnames[test_reg]);
+ }
+ else
+ emit(f,"\n\t%s\tb28\t%s\n",instruction,regnames[test_reg]);
+ }
+ }
+ else
+ {
+ if(isreg(q2))
+ {
+ char instruction[10];
+ sprintf(instruction, "%s", ccs[c-BEQ]);
+ if(instruction[0] == '!')
+ {
+ instruction[0] = ' ';
+ emit(f,"\n\t%s\t%s\t%s\n",instruction,regnames[test_reg],regnames[test_reg2]);
+ }
+ else
+ emit(f,"\n\t%s\t%s\t%s\n",instruction,regnames[p->q2.reg],regnames[test_reg]);
+
+ save_result(f,p);
+ continue;
+ }
+ else
+ {
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmovs\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmovs\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmovs\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ char instruction[10];
+ sprintf(instruction, "%s", ccs[c-BEQ]);
+ if(instruction[0] == '!')
+ {
+ instruction[0] = ' ';
+ emit(f,"\n\t%s\t%s\tb28\n",instruction,regnames[test_reg]);
+ }
+ else
+ emit(f,"\n\t%s\tb28\t%s\n",instruction,regnames[test_reg]);
+ }
+ }
+
+ //emit(f,"\tj%s\t",ccs[c-BEQ]);
+ //if(isreg(q1))
+ //{
+ //emit_obj(f,&p->q1,0);
+ //emit(f,",");
+ //}
+ //emit(f,"%s%d ;\n",labprefix,t);
+
+ // next
+
+ }
+ else
+ {
+ if(p_old->code == BEQ)
+ {
+ emit(f,"\n\trz\t%s\n",regnames[test_reg]);
+ }
+ else if(p_old->code == BNE)
+ {
+ emit(f,"\n\trnz\t%s\n",regnames[test_reg]);
+ }
+ else
+ emit(f,"not sure what to do with %d\n", p_old->code);
+ }
+
+ p = p_old;
+ t=p->typf;
+
+ test_handled = 0;
+
+ emit(f,"\tmov\tb28\t%s%d\n",labprefix,t);
+ emit(f,"\tjnz\tz0\tb28\n");
+ continue;
+ }
+ if(c==TEST)
+ {
+ // printf("found test");
+/* emit(f,"\ttst\t");
+ if(multiple_ccs)
+ emit(f,"%s,",regnames[zreg]);
+ emit_obj(f,&p->q1,t);
+ emit(f," ; %s\n",dt(t));
+ if(multiple_ccs)
+ save_result(f,p); */
+
+ test_reg = zreg;
+ test_reg2 = q2reg;
+
+ if(!isreg(q1))
+ load_reg(f,test_reg,&p->q1,t);
+
+ p_test = p;
+ test_handled = 1;
+
+ continue;
+ }
+ if(c==COMPARE)
+ {
+ test_reg = zreg;
+ test_reg2 = q2reg;
+
+ if(!isreg(q1))
+ load_reg(f,zreg,&p->q1,t);
+
+ p_test = p;
+ test_handled = 0;
+// emit(f, "; compare %s\n", regnames[zreg]);
+ continue;
+ }
+ if(c==OR)
+ {
+ emit(f,"\tmov\tb28\t");
+ emit_obj(f,&p->q2,t);
+
+ emit(f,"\n\tor\t%s b28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c==XOR)
+ {
+ emit(f,"\tmov\tb28\t");
+ emit_obj(f,&p->q2,t);
+
+ emit(f,"\n\txor\t%s b28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c==AND)
+ {
+ emit(f,"\tmov\tb28\t");
+ emit_obj(f,&p->q2,t);
+
+ emit(f,"\n\tand\t%s b28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(c==LSHIFT)
+ {
+ emit(f,"\tmov\tb28\t");
+ emit_obj(f,&p->q2,t);
+
+ emit(f,"\n\tsal\t%s b28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(c==RSHIFT)
+ {
+ emit(f,"\tmov\tb28\t");
+ emit_obj(f,&p->q2,t);
+
+ emit(f,"\n\tsar\t%s b28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(c==ADD) ///////////////////////////////////////// ADDITION
+ {
+ if(!isreg(q1))
+ load_reg(f,zreg,&p->q1,t);
+
+ if(p->q2.flags&KONST)
+ {
+ if(ISFLOAT(t))
+ {
+ char *ds = (char *)&p->q2.val.vfloat;
+ char tmp = ds[0];
+ ds[0] = ds[3];
+ ds[3] = tmp;
+ tmp = ds[1];
+ ds[1] = ds[2];
+ ds[2] = tmp;
+
+ if((*(float *)ds) == 1.0f)
+ {
+ emit(f,"\tincf\t%s\n", regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ }
+ else if(t & UNSIGNED)
+ {
+ if(*(unsigned int *)&p->q2.val == 1)
+ {
+ emit(f,"\tinc\t%s\n", regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ }
+ else
+ {
+ if(*(unsigned int *)&p->q2.val == 1)
+ {
+ emit(f,"\tincs\t%s\n", regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ }
+ }
+
+ if(ISFLOAT(t))
+ {
+ if(isreg(q2))
+ {
+ emit(f,"\n\taddf\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmovf\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmovf\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmovf\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ emit(f,"\n\taddf\t%s b28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ else if(t & UNSIGNED)
+ {
+ if(isreg(q2))
+ {
+ emit(f,"\n\tadd\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmov\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmov\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ emit(f,"\n\tadd\t%s b28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ else
+ {
+ if(isreg(q2))
+ {
+ emit(f,"\n\tadds\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmovs\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmovs\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmovs\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ emit(f,"\n\tadds\t%s b28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ }
+
+ if(c==SUB)
+ {
+ if(!isreg(q1))
+ load_reg(f,zreg,&p->q1,t);
+
+ if(p->q2.flags&KONST)
+ {
+ if(ISFLOAT(t))
+ {
+ char *ds = (char *)&p->q2.val.vfloat;
+ char tmp = ds[0];
+ ds[0] = ds[3];
+ ds[3] = tmp;
+ tmp = ds[1];
+ ds[1] = ds[2];
+ ds[2] = tmp;
+
+ if((*(float *)ds) == 1.0f)
+ {
+ emit(f,"\tdecf\t%s\n", regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ }
+ else if(t & UNSIGNED)
+ {
+ if(*(unsigned int *)&p->q2.val == 1)
+ {
+ emit(f,"\tdec\t%s\n", regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ }
+ else
+ {
+ if(*(unsigned int *)&p->q2.val == 1)
+ {
+ emit(f,"\tdecs\t%s\n", regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ }
+ }
+ if(ISFLOAT(t))
+ {
+ if(isreg(q2))
+ {
+ emit(f,"\n\tsubf\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmovf\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmovf\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmovf\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ emit(f,"\n\tsubf\t%s\tb28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ else if(t & UNSIGNED)
+ {
+ if(isreg(q2))
+ {
+ emit(f,"\n\tsub\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmov\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmov\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ emit(f,"\n\tsub\t%s\tb28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ else
+ {
+ if(isreg(q2))
+ {
+ emit(f,"\n\tsubs\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmovs\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmovs\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmovs\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ emit(f,"\n\tsubs\t%s\tb28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ }
+
+ if(c==MULT)
+ {
+ if(ISFLOAT(t))
+ {
+ if(isreg(q2))
+ {
+ emit(f,"\n\tmulf\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmovf\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmovf\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmovf\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ emit(f,"\n\tmulf\t%s\tb28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ else if(t & UNSIGNED)
+ {
+ if(isreg(q2))
+ {
+ emit(f,"\n\tmul\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmov\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmov\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ emit(f,"\n\tmul\t%s\tb28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ else
+ {
+ if(isreg(q2))
+ {
+ emit(f,"\n\tmuls\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmovs\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmovs\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmovs\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ emit(f,"\n\tmuls\t%s\tb28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+
+ continue;
+ }
+
+ if(c==DIV)
+ {
+ if(ISFLOAT(t))
+ {
+ if(isreg(q2))
+ {
+ emit(f,"\n\tdivf\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmovf\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmovf\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmovf\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ emit(f,"\n\tdivf\t%s\tb28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ else if(t & UNSIGNED)
+ {
+ if(isreg(q2))
+ {
+ emit(f,"\n\tdiv\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmov\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmov\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ emit(f,"\n\tdiv\t%s\tb28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ else
+ {
+ if(isreg(q2))
+ {
+ emit(f,"\n\tdivs\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmovs\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmovs\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmovs\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ emit(f,"\n\tdivs\t%s\tb28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ }
+
+ if(c==MOD)
+ {
+ if(ISFLOAT(t))
+ {
+ if(isreg(q2))
+ {
+ emit(f,"\n\tmodf\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmovf\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmovf\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmovf\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ emit(f,"\n\tmodf\t%s\tb28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ else if(t & UNSIGNED)
+ {
+ if(isreg(q2))
+ {
+ emit(f,"\n\tmod\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmov\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmov\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ emit(f,"\n\tmod\t%s\tb28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ else
+ {
+ if(isreg(q2))
+ {
+ emit(f,"\n\tmods\t%s\t%s\n",/*dt(t),*/regnames[zreg],regnames[p->q2.reg]);
+ save_result(f,p);
+ continue;
+ }
+
+ if(((p->q2.flags&VAR)&&!(p->q2.flags®)) && (p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER))
+ {
+ unsigned long offset = real_offset(&p->q2);
+ if(offset == 0)
+ {
+ emit(f,"\tmovs\tb28\t[z2]\n");
+ }
+ else
+ {
+ emit(f,"\tmov\tb28\t%ld ; get from stack\n", offset);
+ emit(f,"\tmov\tb29\tz2\n");
+ emit(f,"\tsub\tb29\tb28\n");
+ emit(f,"\tmovs\tb28\t[b29]\n");
+ }
+ }
+ else
+ {
+ emit(f,"\tmovs\tb28\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+
+ emit(f,"\n\tmods\t%s\tb28\n",/*dt(t),*/regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ }
+
+ pric2(stdout,p);
+ ierror(0);
+ }
+ function_bottom(f,v,localsize);
+ if(stack_valid)
+ {
+ if(!v->fi)
+ v->fi=new_fi();
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=stack;
+ }
+ emit(f," ; stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int code,int typ)
+{
+ return 1;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+ int f;
+ f=t->flags&NQ;
+ if(f==CHAR)
+ {
+ if(m->regs8>=NUM_8BIT)
+ return 0;
+ else
+ return FIRST_8BIT+m->regs8++;
+ }
+ if(f==SHORT)
+ {
+ if(m->regs16>=NUM_16BIT)
+ return 0;
+ else
+ return FIRST_16BIT+m->regs16++;
+ }
+ if(f==INT || f==LONG || f==POINTER || f==FLOAT)
+ {
+ if(m->regs32>=NUM_32BIT)
+ return 0;
+ else
+ return FIRST_32BIT+m->regs32++;
+ }
+ if(f==DOUBLE || f==LDOUBLE || f==LLONG){
+ if(m->regs64>=NUM_64BIT)
+ return 0;
+ else
+ return FIRST_64BIT+m->regs64++;
+ }
+ return 0;
+}
+
+int handle_pragma(const char *s)
+{
+ return 0;
+}
+
+void cleanup_cg(FILE *f)
+{
+ if(!f)
+ return;
+
+}
+
+void cleanup_db(FILE *f)
+{
+ if(f)
+ section=-1;
+}
+
+/*
+C registers:
+b28 - temp - store var during calculation/comparison
+b29 - temp - store address during jump
+b30 - temp store address of parameters
+b31 - temp store addresses to jump to
+
+a0 - 16 bit 4
+a1 - 16 bit 5
+a2 - 16 bit 6
+a3 - 16 bit 7
+a4 - 16 bit 8
+a5 - 16 bit 9
+a6 - 16 bit 10
+a7 - 16 bit 11
+a8 - 16 bit 12
+a9 - 16 bit 13
+b5 - 32 bit 14
+b6 - 32 bit 15
+b7 - 32 bit 16
+b8 - 32 bit 17
+b9 - 32 bit 18
+b10 - 32 bit 19
+b11 - 32 bit 20
+b12 - 32 bit 21
+b13 - 32 bit 22
+b14 - 32 bit 23
+b15 - 32 bit 24
+b16 - 32 bit 25
+b17 - 32 bit 26
+c9 - 64 bit 27
+c10 - 64 bit 28
+c11 - 64 bit 29
+c12 - 64 bit 30
+c13 - 64 bit 31
+
+h0 - 8bit 32
+h1 - 8bit 33
+h2 - 8bit 34
+h3 - 8bit 35
+*/
diff --git a/machines/messiahtron/machine.dt b/machines/messiahtron/machine.dt
new file mode 100755
index 0000000..526c8d4
--- /dev/null
+++ b/machines/messiahtron/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/messiahtron/machine.h b/machines/messiahtron/machine.h
new file mode 100755
index 0000000..acab9ae
--- /dev/null
+++ b/machines/messiahtron/machine.h
@@ -0,0 +1,184 @@
+/* Example backend for vbcc, it models a generic 32bit RISC or CISC
+ CPU.
+
+ Configurable at build-time are:
+ - number of (32bit) general-purpose-registers
+ - number of (64bit) floating-point-registers
+ - number of (8bit) condition-code-registers
+ - mechanism for stack-arguments (moving ot fixed sp)
+
+ It allows to select as run-time-options:
+ - two- or three-address code
+ - memory operands or load-store-architecture
+ - number of register-arguments
+ - number of caller-save-registers
+*/
+
+/* buil-time configurable options: */
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef MAXINT
+#undef MAX_TYPE
+
+#define CHAR 1
+#define SHORT 2
+#define INT 3
+#define LONG 4
+#define LLONG 5
+#define FLOAT 6
+#define DOUBLE 7
+#define LDOUBLE 8
+#define VOID 9
+#define POINTER 10
+#define ARRAY 11
+#define STRUCT 12
+#define UNION 13
+#define ENUM 14
+#define FUNKT 15
+#define MAXINT 16 /* should not be accesible to application */
+#define MAX_TYPE MAXINT
+
+
+//#define NUM_FIXED 4
+#define NUM_16BIT 10
+#define NUM_32BIT 13
+#define NUM_64BIT 5
+#define NUM_8BIT 4
+
+#include "dt.h"
+
+/* internally used by the backend */
+//#define FIRST_FIXED 1
+//#define LAST_FIXED (FIRST_FIXED+NUM_FIXED-1)
+#define FIRST_16BIT 1//(LAST_FIXED+1)
+#define LAST_16BIT (FIRST_16BIT+NUM_16BIT-1)
+#define FIRST_32BIT (LAST_16BIT+1)
+#define LAST_32BIT (FIRST_32BIT+NUM_32BIT-1)
+#define FIRST_64BIT (LAST_32BIT+1)
+#define LAST_64BIT (FIRST_64BIT+NUM_64BIT-1)
+#define FIRST_8BIT (LAST_64BIT+1)
+#define LAST_8BIT (FIRST_8BIT+NUM_8BIT-1)
+#define STACK_POINTER (LAST_8BIT+1)
+
+// #define FIXED_SP 1
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Currently possible are (const,gpr) and (gpr,gpr) */
+struct AddressingMode{
+ int flags;
+ int base;
+ long offset;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR NUM_16BIT+NUM_32BIT+NUM_64BIT+NUM_8BIT+1
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 20
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P CHAR
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 1
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 0
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+/* Parameters are sometimes passed in registers without __reg. */
+#define HAVE_REGPARMS 1
+
+/* Parameters on the stack should be pushed in order rather than */
+/* in reverse order. */
+#define ORDERED_PUSH 1
+
+/* Structure for reg_parm(). */
+struct reg_handle{
+ unsigned long regs8;
+ unsigned long regs16;
+ unsigned long regs32;
+ unsigned long regs64;
+};
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt
+ register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output, this can be used to do
+ peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/* We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+ optimizations on code which can already be implemented by efficient
+ assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+ etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#undef HAVE_INT_SIZET
+
+/* we do not need register-pairs */
+#undef HAVE_REGPAIRS
+
diff --git a/machines/minx/machine.c b/machines/minx/machine.c
new file mode 100755
index 0000000..2417521
--- /dev/null
+++ b/machines/minx/machine.c
@@ -0,0 +1,1021 @@
+/* Example backend for vbcc, it models a generic 32bit RISC or CISC
+ CPU.
+
+ Configurable at build-time are:
+ - number of (32bit) general-purpose-registers
+ - number of (64bit) floating-point-registers
+ - number of (8bit) condition-code-registers
+ - mechanism for stack-arguments (moving ot fixed sp)
+
+ It allows to select as run-time-options:
+ - two- or three-address code
+ - memory operands or load-store-architecture
+ - number of register-arguments
+ - number of caller-save-registers
+ */
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc generic code-generator V0.01 for Minx (c) in 2001 by zoranc";
+
+/* Commandline-flags the code-generator accepts:
+ 0: just a flag
+ VALFLAG: a value must be specified
+ STRINGFLAG: a string can be specified
+ FUNCFLAG: a function will be called
+ apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]={0,0,
+ VALFLAG,VALFLAG,VALFLAG,
+ 0,0,
+ VALFLAG,VALFLAG,0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+ they collide with the frontend */
+char *g_flags_name[MAXGF]={"three-addr","load-store",
+ "volatile-gprs","volatile-fprs","volatile-ccrs",
+ "imm-ind","gpr-ind",
+ "gpr-args","fpr-args","use-commons"};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. will be initialized in init_cg(),
+ register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+ estimated cost-saving can be obtained by several registers, the
+ one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__interrupt",0};
+
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+#define THREE_ADDR (g_flags[0]&USEDFLAG)
+#define LOAD_STORE (g_flags[1]&USEDFLAG)
+#define VOL_GPRS ((g_flags[2]&USEDFLAG)?g_flags_val[2].l:NUM_GPRS/2)
+#define VOL_FPRS ((g_flags[3]&USEDFLAG)?g_flags_val[3].l:NUM_FPRS/2)
+#define VOL_CCRS ((g_flags[4]&USEDFLAG)?g_flags_val[4].l:NUM_CCRS/2)
+#define IMM_IND ((g_flags[5]&USEDFLAG)?1:0)
+#define GPR_IND ((g_flags[6]&USEDFLAG)?2:0)
+#define GPR_ARGS ((g_flags[7]&USEDFLAG)?g_flags_val[7].l:0)
+#define FPR_ARGS ((g_flags[8]&USEDFLAG)?g_flags_val[8].l:0)
+#define USE_COMMONS (g_flags[9]&USEDFLAG)
+
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]= {1,1,2,4,4,4,4,8,8,1,4,1,1,1,4,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp={LONG},ldbl={DOUBLE},lchar={CHAR};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+ "__GENERIC__",
+ 0};
+
+/* special registers */
+static int sp; /* Stackpointer */
+static int t1,t2,t3; /* temporary gprs */
+static int f1,f2,f3; /* temporary fprs */
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\t.text\n",
+*dataname="\t.data\n",
+*bssname="",
+*rodataname="\t.section\t.rodata\n";
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+#if FIXED_SP
+/* variables to calculate the size and partitioning of the stack-frame
+ in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+#else
+/* variables to keep track of the current stack-offset in the case of
+ a moving stack-pointer */
+static long notpopped,dontpop,stackoffset,maxpushed;
+#endif
+
+static long localsize,rsavesize,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+ stack-pointer; we use a layout like this:
+ ------------------------------------------------
+ | arguments to this function |
+ ------------------------------------------------
+ | return-address [size=4] |
+ ------------------------------------------------
+ | caller-save registers [size=rsavesize] |
+ ------------------------------------------------
+ | local variables [size=localsize] |
+ ------------------------------------------------
+ | arguments to called functions [size=argsize] |
+ ------------------------------------------------
+ All sizes will be aligned as necessary.
+ In the case of FIXED_SP, the stack-pointer will be adjusted at
+ function-entry to leave enough space for the arguments and have it
+ aligned to 16 bytes. Therefore, when calling a function, the
+ stack-pointer is always aligned to 16 bytes.
+ For a moving stack-pointer, the stack-pointer will usually point
+ to the bottom of the area for local variables, but will move while
+ arguments are put on the stack.
+
+ This is just an example layout. Other layouts are also possible.
+ */
+
+static long real_offset(struct obj *o)
+{
+ long off=zm2l(o->v->offset);
+ if(off<0){
+ /* function parameter */
+ off=localsize+rsavesize+4-off-zm2l(maxalign);
+ }
+
+#if FIXED_SP
+ off+=argsize;
+#else
+ off+=stackoffset;
+#endif
+ off+=zm2l(o->val.vmax);
+ return off;
+}
+
+/* Initializes an addressing-mode structure and returns a pointer to
+ that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ am.offset=offset;
+ return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+ char *sec;
+ if(!v->vattr) return 0;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return 0;
+ sec+=strlen("section(");
+ emit(f,"\t.section\t");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/* Generates code to load the address of a variable into register r. */
+{
+ if(!(o->flags&VAR)) ierror(0);
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+ long off=real_offset(o);
+ if(THREE_ADDR){
+ emit(f,"\tadd.%s\t%s,%s,%ld\n",dt(POINTER),regnames[r],regnames[sp],off);
+ }else{
+ emit(f,"\tmov.%s\t%s,%s\n",dt(POINTER),regnames[r],regnames[sp]);
+ if(off)
+ emit(f,"\tadd.%s\t%s,%ld\n",dt(POINTER),regnames[r],off);
+ }
+ }else{
+ emit(f,"\tmov.%s\t%s,",dt(POINTER),regnames[r]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }
+}
+/* Generates code to load a memory object into register r. tmp is a
+ general purpose register which may be used. tmp can be r. */
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+ type&=NU;
+ if(o->flags&VARADR){
+ load_address(f,r,o,POINTER);
+ }else{
+ if((o->flags&(REG|DREFOBJ))==REG&&o->reg==r)
+ return;
+ emit(f,"\tmov.%s\t%s,",dt(type),regnames[r]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }
+}
+
+/* Generates code to store register r into memory object o. */
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+ type&=NQ;
+ emit(f,"\tmov.%s\t",dt(type));
+ emit_obj(f,o,type);
+ emit(f,",%s\n",regnames[r]);
+}
+
+/* Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+
+static struct IC *preload(FILE *,struct IC *);
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
+
+/* Does some pre-processing like fetching operands from memory to
+ registers etc. */
+static struct IC *preload(FILE *f,struct IC *p)
+{
+ int r;
+
+ if(isreg(q1))
+ q1reg=p->q1.reg;
+ else
+ q1reg=0;
+
+ if(isreg(q2))
+ q2reg=p->q2.reg;
+ else
+ q2reg=0;
+
+ if(isreg(z)){
+ zreg=p->z.reg;
+ }else{
+ if(ISFLOAT(ztyp(p)))
+ zreg=f1;
+ else
+ zreg=t1;
+ }
+
+ if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am){
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,t1,&p->q1,q1typ(p));
+ p->q1.reg=t1;
+ p->q1.flags|=(REG|DREFOBJ);
+ }
+ if(p->q1.flags&&LOAD_STORE&&!isreg(q1)){
+ if(ISFLOAT(q1typ(p)))
+ q1reg=f1;
+ else
+ q1reg=t1;
+ load_reg(f,q1reg,&p->q1,q1typ(p));
+ p->q1.reg=q1reg;
+ p->q1.flags=REG;
+ }
+
+ if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am){
+ p->q2.flags&=~DREFOBJ;
+ load_reg(f,t1,&p->q2,q2typ(p));
+ p->q2.reg=t1;
+ p->q2.flags|=(REG|DREFOBJ);
+ }
+ if(p->q2.flags&&LOAD_STORE&&!isreg(q2)){
+ if(ISFLOAT(q2typ(p)))
+ q2reg=f2;
+ else
+ q2reg=t2;
+ load_reg(f,q2reg,&p->q2,q2typ(p));
+ p->q2.reg=q2reg;
+ p->q2.flags=REG;
+ }
+ return p;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+ if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
+ p->z.flags&=~DREFOBJ;
+ load_reg(f,t2,&p->z,POINTER);
+ p->z.reg=t2;
+ p->z.flags|=(REG|DREFOBJ);
+ }
+ if(isreg(z)){
+ if(p->z.reg!=zreg)
+ emit(f,"\tmov.%s\t%s,%s\n",dt(ztyp(p)),regnames[p->z.reg],regnames[zreg]);
+ }else{
+ store_reg(f,zreg,&p->z,ztyp(p));
+ }
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+ if(p->am){
+ if(p->am->flags&GPR_IND) emit(f,"(%s,%s)",regnames[p->am->offset],regnames[p->am->base]);
+ if(p->am->flags&IMM_IND) emit(f,"(%ld,%s)",p->am->offset,regnames[p->am->base]);
+ return;
+ }
+ if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if(p->flags&DREFOBJ) emit(f,"(");
+ if(p->flags®){
+ emit(f,"%s",regnames[p->reg]);
+ }else if(p->flags&VAR) {
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+ emit(f,"%ld(%s)",real_offset(p),regnames[sp]);
+ else{
+ if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ }
+ }
+ if(p->flags&KONST){
+ emitval(f,&p->val,t&NU);
+ }
+ if(p->flags&DREFOBJ) emit(f,")");
+}
+
+/* Test if there is a sequence of FREEREGs containing FREEREG reg.
+ Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+ while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+ if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+ p=p->next;
+ }
+ return 0;
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+ rsavesize=0;
+ if(!special_section(f,v)&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ if(offset)
+ emit(f,"\tsub.i\tgpr0,%ld\n", offset);
+}
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+ if(offset)
+ emit(f,"\tadd.i\tgpr0,%ld\n", offset);
+ emit(f,ret);
+}
+
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+int init_cg(void)
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(8L);
+ char_bit=l2zm(8L);
+
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+
+ regnames[0]="noreg";
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"gpr%d",i-FIRST_GPR);
+ regsize[i]=l2zm(4L);
+ regtype[i]=<yp;
+ }
+ for(i=FIRST_FPR;i<=LAST_FPR;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"fpr%d",i-FIRST_FPR);
+ regsize[i]=l2zm(8L);
+ regtype[i]=&ldbl;
+ }
+ for(i=FIRST_CCR;i<=LAST_CCR;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"ccr%d",i-FIRST_CCR);
+ regsize[i]=l2zm(1L);
+ regtype[i]=&lchar;
+ }
+
+ /* Use multiple ccs. */
+ multiple_ccs=0;
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LONG]=t_min(INT);
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(31L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=ul2zum(2147483647UL);
+ t_max[LONG]=t_max(INT);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=ul2zum(4294967295UL);
+ tu_max[LONG]=t_max(UNSIGNED|INT);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ /* This is not optimal but simple. */
+ sp=FIRST_GPR;
+ t1=FIRST_GPR+1;
+ t2=FIRST_GPR+2;
+ f1=FIRST_FPR;
+ f2=FIRST_FPR+1;
+ regsa[t1]=regsa[t2]=1;
+ regsa[f1]=regsa[f2]=1;
+ regsa[sp]=1;
+ regscratch[t1]=regscratch[t2]=0;
+ regscratch[f1]=regscratch[f2]=0;
+ regscratch[sp]=0;
+
+ for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++)
+ regscratch[i]=1;
+ for(i=FIRST_FPR;i<=LAST_FPR-VOL_FPRS;i++)
+ regscratch[i]=1;
+ for(i=FIRST_CCR;i<=LAST_CCR-VOL_CCRS;i++)
+ regscratch[i]=1;
+
+ target_macros=marray;
+
+
+ return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+/* A pointer MUST be returned in a register. The code-generator */
+/* has to simulate a pseudo register if necessary. */
+{
+ if(ISFLOAT(t->flags))
+ return FIRST_FPR+2;
+ if(ISSTRUCT(t->flags)||ISUNION(t->flags))
+ return 0;
+ if(zmleq(szof(t),l2zm(4L)))
+ return FIRST_GPR+3;
+ else
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+ register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+ int c=p->code;
+ if(o->flags&VKONST){
+ if(!LOAD_STORE)
+ return 0;
+ if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
+ return 4;
+ else
+ return 2;
+ }
+ if(o->flags&DREFOBJ)
+ return 4;
+ if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+ if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+ return 2;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(r==0)
+ return 0;
+ t&=NQ;
+ if(t==0&&r>=FIRST_CCR&&r<=LAST_CCR)
+ return 1;
+ if(ISFLOAT(t)&&r>=FIRST_FPR&&r<=LAST_FPR)
+ return 1;
+ if(t==POINTER&&r>=FIRST_GPR&&r<=LAST_GPR)
+ return 1;
+ if(t>=CHAR&&t<=LONG&&r>=FIRST_GPR&&r<=LAST_GPR)
+ return 1;
+ return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* On the PowerPC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op=o&NQ,tp=t&NQ;
+ if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
+ return 0;
+ if(op==DOUBLE&&tp==LDOUBLE) return 0;
+ if(op==LDOUBLE&&tp==DOUBLE) return 0;
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ if(newobj&§ion!=SPECIAL)
+ emit(f,"%ld\n",zm2l(size));
+ else
+ emit(f,"\t.space\t%ld\n",zm2l(size));
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ if(zm2l(align)>1) emit(f,"\t.align\t2\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;char *sec;
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(v->clist||section==SPECIAL){
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }else
+ emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+ newobj=1;
+ }
+ if(v->storage_class==EXTERN){
+ emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+ if(v->flags&(DEFINED|TENTATIVE)){
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(v->clist||section==SPECIAL){
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ emit(f,"\tdc.%s\t",dt(t&NQ));
+ if(!p->tree){
+ if(ISFLOAT(t)){
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ if((t&NQ)!=FLOAT){
+ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ }else{
+ emitval(f,&p->val,t&NU);
+ }
+ }else{
+ emit_obj(f,&p->tree->o,t&NU);
+ }
+ emit(f,"\n");newobj=0;
+}
+
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/* The main code-generation. */
+{
+ int c,t,i;
+ struct IC *m;
+ argsize=0;
+ if(DEBUG&1) printf("gen_code()\n");
+ for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+ maxpushed=0;
+
+ /*FIXME*/
+ ret="\trts\n";
+
+ for(m=p;m;m=m->next){
+ c=m->code;t=m->typf&NU;
+ if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
+ if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
+
+ /* convert MULT/DIV/MOD with powers of two */
+ if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+ eval_const(&m->q2.val,t);
+ i=pof2(vmax);
+ if(i){
+ if(c==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ m->code=AND;
+ }else{
+ vmax=l2zm(i-1);
+ if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+ }
+ c=m->code;
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ if(c==AND){
+ insert_const(&m->q2.val,t);
+ }else{
+ insert_const(&m->q2.val,INT);
+ p->typf2=INT;
+ }
+ }
+ }
+#if FIXED_SP
+ if(c==CALL&&argsize<zm2l(m->q2.val.vmax)) argsize=zm2l(m->q2.val.vmax);
+#endif
+ }
+
+ for(c=1;c<=MAXR;c++){
+ if(regsa[c]||regused[c]){
+ BSET(regs_modified,c);
+ }
+ }
+
+ localsize=(zm2l(offset)+3)/4*4;
+#if FIXED_SP
+ /*FIXME: adjust localsize to get an aligned stack-frame */
+#endif
+
+ function_top(f,v,localsize);
+
+#if FIXED_SP
+ pushed=0;
+#endif
+
+ for(;p;p=p->next){
+ c=p->code;t=p->typf;
+ if(c==NOP) {p->z.flags=0;continue;}
+ if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
+ if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
+ if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);continue;}
+ if(c==BRA){
+ if(t==exit_label)
+ emit(f,ret);
+ else
+ emit(f,"\tb\t%s%d\n",labprefix,t);
+ continue;
+ }
+ if(c>=BEQ&&c<BRA){
+ emit(f,"\tb%s\t",ccs[c-BEQ]);
+ if(isreg(q1)){
+ emit_obj(f,&p->q1,0);
+ emit(f,",");
+ }
+ emit(f,"%s%d\n",labprefix,t);
+ continue;
+ }
+ if(c==MOVETOREG){
+ load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+ continue;
+ }
+ if(c==MOVEFROMREG){
+ store_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+ continue;
+ }
+ if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+ ierror(0);
+ }
+ p=preload(f,p);
+ c=p->code;
+ if(c==SUBPFP) c=SUB;
+ if(c==ADDI2P) c=ADD;
+ if(c==SUBIFP) c=SUB;
+ if(c==CONVERT){
+ if(ISFLOAT(q1typ(p))||ISFLOAT(ztyp(p))) ierror(0);
+ if(sizetab[q1typ(p)&NQ]<sizetab[ztyp(p)&NQ]){
+ if(q1typ(p)&UNSIGNED)
+ emit(f,"\tzext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+ else
+ emit(f,"\tsext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+ }
+ save_result(f,p);
+ continue;
+ }
+ if(c==KOMPLEMENT){
+ load_reg(f,zreg,&p->q1,t);
+ emit(f,"\tcpl.%s\t%s\n",dt(t),regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c==SETRETURN){
+ load_reg(f,p->z.reg,&p->q1,t);
+ BSET(regs_modified,p->z.reg);
+ continue;
+ }
+ if(c==GETRETURN){
+ if(p->q1.reg){
+ zreg=p->q1.reg;
+ save_result(f,p);
+ }else
+ p->z.flags=0;
+ continue;
+ }
+ if(c==CALL){
+ int reg;
+ /*FIXME*/
+#if 0
+ if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+ if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+ stack=framesize+zum2ul(p->q1.v->fi->stack1);
+ }else
+ stack_valid=0;
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ }else{
+ emit(f,"\tcall\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ /*FIXME*/
+#if FIXED_SP
+ pushed-=zm2l(p->q2.val.vmax);
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+ bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+ }else{
+ int i;
+ for(i=1;i<=MAXR;i++){
+ if(regscratch[i]) BSET(regs_modified,i);
+ }
+ }
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(t==0) ierror(0);
+ if(c==PUSH){
+#if FIXED_SP
+ emit(f,"\tmov.%s\t%ld(%s),",dt(t),pushed,regnames[sp]);
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ pushed+=zm2l(p->q2.val.vmax);
+#else
+ emit(f,"\tpush.%s\t",dt(t));
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ /*pushed += zm2l(p->q2.val.vmax);*/
+#endif
+ continue;
+ }
+ if(c==ASSIGN){
+ load_reg(f,zreg,&p->q1,t);
+ save_result(f,p);
+ }
+ continue;
+ }
+ if(c==ADDRESS){
+ load_address(f,zreg,&p->q1,POINTER);
+ save_result(f,p);
+ continue;
+ }
+ if(c==MINUS){
+ load_reg(f,zreg,&p->q1,t);
+ emit(f,"\tneg.%s\t%s\n",dt(t),regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c==TEST){
+ emit(f,"\ttst.%s\t",dt(t));
+ if(multiple_ccs)
+ emit(f,"%s,",regnames[zreg]);
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ if(multiple_ccs)
+ save_result(f,p);
+ continue;
+ }
+ if(c==COMPARE){
+ emit(f,"\tcmp.%s\t",dt(t));
+ if(multiple_ccs)
+ emit(f,"%s,",regnames[zreg]);
+ emit_obj(f,&p->q1,t);
+ emit(f,",");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ if(multiple_ccs)
+ save_result(f,p);
+ continue;
+ }
+ if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)){
+ if(!THREE_ADDR)
+ load_reg(f,zreg,&p->q1,t);
+ if(c>=OR&&c<=AND)
+ emit(f,"\t%s.%s\t%s,",logicals[c-OR],dt(t),regnames[zreg]);
+ else
+ emit(f,"\t%s.%s\t%s,",arithmetics[c-LSHIFT],dt(t),regnames[zreg]);
+ if(THREE_ADDR){
+ emit_obj(f,&p->q1,t);
+ emit(f,",");
+ }
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ save_result(f,p);
+ continue;
+ }
+ pric2(stdout,p);
+ ierror(0);
+ }
+ function_bottom(f,v,localsize);
+ if(stack_valid){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=stack;
+ }
+ emit(f,"# stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int c, int typ)
+{
+ if(c==COMPARE||c==ADD||c==SUB||c==AND||c==OR||c==XOR) return 1;
+ return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+ int f;
+ f=t->flags&NQ;
+ if(f<=LONG||f==POINTER){
+ if(m->gregs>=GPR_ARGS)
+ return 0;
+ else
+ return FIRST_GPR+3+m->gregs++;
+ }
+ if(ISFLOAT(f)){
+ if(m->fregs>=FPR_ARGS)
+ return 0;
+ else
+ return FIRST_FPR+2+m->fregs++;
+ }
+ return 0;
+}
+
+int handle_pragma(const char *s)
+{
+}
+void cleanup_cg(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+ if(f) section=-1;
+}
+
diff --git a/machines/minx/machine.dt b/machines/minx/machine.dt
new file mode 100755
index 0000000..736fdec
--- /dev/null
+++ b/machines/minx/machine.dt
@@ -0,0 +1,14 @@
+S8BS
+S8BU
+S8BS
+S8BU
+S16BSLE
+S16BULE
+S32BSLE
+S32BULE
+S32BSLE
+S32BULE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S32BULE
diff --git a/machines/minx/machine.h b/machines/minx/machine.h
new file mode 100755
index 0000000..25626fa
--- /dev/null
+++ b/machines/minx/machine.h
@@ -0,0 +1,136 @@
+/* Example backend for vbcc, it models a generic 32bit RISC or CISC
+ CPU.
+
+ Configurable at build-time are:
+ - number of (32bit) general-purpose-registers
+ - number of (64bit) floating-point-registers
+ - number of (8bit) condition-code-registers
+ - mechanism for stack-arguments (moving ot fixed sp)
+
+ It allows to select as run-time-options:
+ - two- or three-address code
+ - memory operands or load-store-architecture
+ - number of register-arguments
+ - number of caller-save-registers
+*/
+
+/* buil-time configurable options: */
+#define NUM_GPRS 4
+#define NUM_FPRS 1
+#define NUM_CCRS 1
+#define FIXED_SP 1
+
+#include "dt.h"
+
+/* internally used by the backend */
+#define FIRST_GPR 1
+#define LAST_GPR (FIRST_GPR+NUM_GPRS-1)
+#define FIRST_FPR (LAST_GPR+1)
+#define LAST_FPR (FIRST_FPR+NUM_FPRS-1)
+#define FIRST_CCR (LAST_FPR+1)
+#define LAST_CCR (FIRST_CCR+NUM_CCRS-1)
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Currently possible are (const,gpr) and (gpr,gpr) */
+struct AddressingMode{
+ int flags;
+ int base;
+ long offset;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR NUM_GPRS+NUM_FPRS+NUM_CCRS
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 20
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P INT
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 0
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 1
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+/* Parameters are sometimes passed in registers without __reg. */
+#define HAVE_REGPARMS 1
+
+/* Parameters on the stack should be pushed in order rather than */
+/* in reverse order. */
+#define ORDERED_PUSH FIXED_SP
+
+/* Structure for reg_parm(). */
+struct reg_handle{
+ unsigned long gregs;
+ unsigned long fregs;
+};
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt
+ register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output, this can be used to do
+ peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/* We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+ optimizations on code which can already be implemented by efficient
+ assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+ etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#undef HAVE_INT_SIZET
+
+/* we do not need register-pairs */
+#undef HAVE_REGPAIRS
+
diff --git a/machines/pm/emit.h b/machines/pm/emit.h
new file mode 100755
index 0000000..aa11b2e
--- /dev/null
+++ b/machines/pm/emit.h
@@ -0,0 +1,7 @@
+
+/* automaticaly generated by process_all.h; do not edit it */
+
+#include "emit_mult.h"
+#include "emit_div_mod.h"
+#include "emit_start.h"
+#include "emit_end.h"
diff --git a/machines/pm/emit_div_mod.h b/machines/pm/emit_div_mod.h
new file mode 100755
index 0000000..c9c6129
--- /dev/null
+++ b/machines/pm/emit_div_mod.h
@@ -0,0 +1,69 @@
+
+/* automaticaly generated from the file div_mod.asm do not modify */
+
+static void emit_div_mod(FILE *f)
+{
+ emit(f,"vbcc___div_mod16x16_16:\n");
+ emit(f,"\tpush\tx\n");
+ emit(f,"\tpush\ty\n");
+ emit(f,"\tmov\tx, 0\n");
+ emit(f,"\tcmp\tba, 0\n");
+ emit(f,"\tjns\tvbcc___dm_banotneg\n");
+ emit(f,"\tnot\ta\n");
+ emit(f,"\tnot\tb\n");
+ emit(f,"\tinc\tba\n");
+ emit(f,"\tadd\tx, 0x0011\n");
+ emit(f,"vbcc___dm_banotneg:\n");
+ emit(f,"\txchg\tba, hl\n");
+ emit(f,"\tcmp\tba, 0\n");
+ emit(f,"\tjns\tvbcc___dm_hlnotneg\n");
+ emit(f,"\tnot\ta\n");
+ emit(f,"\tnot\tb\n");
+ emit(f,"\tinc\tba\n");
+ emit(f,"\tinc\tx\n");
+ emit(f,"vbcc___dm_hlnotneg:\n");
+ emit(f,"\txchg\tba, hl\n");
+ emit(f,"\tpush\tx\n");
+ emit(f,"\tmov\tx, 0\n");
+ emit(f,"\tmov\ty, 1\n");
+ emit(f,"vbcc___dm_shiftloop:\n");
+ emit(f,"\tshl\ta\n");
+ emit(f,"\trolc\tb\n");
+ emit(f,"\txchg\tba, x\n");
+ emit(f,"\trolc\ta\n");
+ emit(f,"\trolc\tb\n");
+ emit(f,"\txchg\tba, x\n");
+ emit(f,"\tsub\tx, hl\n");
+ emit(f,"\tjns\tvbcc___dm_resnotneg\n");
+ emit(f,"\tadd\tx, hl\n");
+ emit(f,"vbcc___dm_resnotneg:\n");
+ emit(f,"\txchg\tba, y\n");
+ emit(f,"\trolc\ta\n");
+ emit(f,"\trolc\tb\n");
+ emit(f,"\txchg\tba, y\n");
+ emit(f,"\tjc\tvbcc___dm_done\n");
+ emit(f,"\tjmp\tvbcc___dm_shiftloop\n");
+ emit(f,"vbcc___dm_done:\n");
+ emit(f,"\tpop\tba\n");
+ emit(f,"\ttst\ta, 0x10\n");
+ emit(f,"\txchg\tba, x\n");
+ emit(f,"\tjz\tvbcc___dm_modnotneg\n");
+ emit(f,"\tnot\ta\n");
+ emit(f,"\tnot\tb\n");
+ emit(f,"\tinc\tba\n");
+ emit(f,"vbcc___dm_modnotneg:\n");
+ emit(f,"\tmov\thl, ba\n");
+ emit(f,"\tmov\tba, x\n");
+ emit(f,"\ttst\ta, 0x01\n");
+ emit(f,"\tmov\tba, y\n");
+ emit(f,"\tjz\tvbcc___dm_resnonegate\n");
+ emit(f,"\tinc\tba\n");
+ emit(f,"\tjmp\tvbcc___dm_resnegate\n");
+ emit(f,"vbcc___dm_resnonegate:\n");
+ emit(f,"\tnot\tb\n");
+ emit(f,"\tnot\ta\n");
+ emit(f,"vbcc___dm_resnegate:\n");
+ emit(f,"\tpop\ty\n");
+ emit(f,"\tpop\tx\n");
+ emit(f,"\tret\n");
+}
diff --git a/machines/pm/emit_end.h b/machines/pm/emit_end.h
new file mode 100755
index 0000000..2a77b2e
--- /dev/null
+++ b/machines/pm/emit_end.h
@@ -0,0 +1,20 @@
+
+/* automaticaly generated from the file end.asm do not modify */
+
+static void emit_end(FILE *f)
+{
+ if(!used_interrupt[15]) {
+ emit(f, "%s15:\n", int_handler_prefix);
+ used_interrupt[15] = (1);
+ }
+ emit(f,"\tmovb\t[nn+0x29], (1<<7)\n");
+ emit(f,"\ttest\t[nn+0x52], (1<<7)\n");
+ emit(f,"\tjnz\tvbcc___noturnoff\n");
+ emit(f,"\tcint\t0x24\n");
+ emit(f,"vbcc___noturnoff:\n");
+ emit(f,"\treti\n");
+ emit_unised_irq_labels(f);
+ emit(f,"\treti\n");
+ emit_mult(f);
+ emit_div_mod(f);
+}
diff --git a/machines/pm/emit_mult.h b/machines/pm/emit_mult.h
new file mode 100755
index 0000000..35012be
--- /dev/null
+++ b/machines/pm/emit_mult.h
@@ -0,0 +1,23 @@
+
+/* automaticaly generated from the file mult.asm do not modify */
+
+static void emit_mult(FILE *f)
+{
+ emit(f,"vbcc___mul16x16_16:\n");
+ emit(f,"\tpush\thl\n");
+ emit(f,"\tmul\tl, a\n");
+ emit(f,"\tpush\thl\n");
+ emit(f,"\tmov\thl,[sp+3]\n");
+ emit(f,"\tmul\tl, a\n");
+ emit(f,"\tmov\ta, b\n");
+ emit(f,"\tmov\tb, l\n");
+ emit(f,"\tmov\thl, [sp+2]\n");
+ emit(f,"\tmul\tl, a\n");
+ emit(f,"\tmov\ta, l\n");
+ emit(f,"\tadd\ta, b\n");
+ emit(f,"\tmov\tb, a\n");
+ emit(f,"\txor\ta, a\n");
+ emit(f,"\tpop\thl\n");
+ emit(f,"\tadd\tba, hl\n");
+ emit(f,"\tpop\thl\n");
+ emit(f,"\tret\n");}
diff --git a/machines/pm/emit_start.h b/machines/pm/emit_start.h
new file mode 100755
index 0000000..6d7d79e
--- /dev/null
+++ b/machines/pm/emit_start.h
@@ -0,0 +1,44 @@
+
+/* automaticaly generated from the file start.asm do not modify */
+
+static void emit_start(FILE *f)
+{
+ emit(f,".org 0x2100\n");
+ emit(f,".db \"MN\"\n");
+ emit_irq_vectors(f);
+ emit(f,".orgfill 0x21A4\n");
+ emit(f,".db \"NINTENDO\"\n");
+ emit(f,".db \"%s\"\n", game_id);
+ emit(f,".db \"%s\"\n", game_name);
+ emit(f,".orgfill 0x21BC\n");
+ emit(f,".db \"2P\"\n");
+ emit(f,".orgfill 0x21D0\n");
+ emit(f,"vbcc___start_rom_vars:\n");
+ emit(f,".org 0x1000\n");
+ emit(f,"vbcc___start_ram_vars:\n");
+ emit(f,".org 0x2000\n");
+ emit(f,"vbcc___end_ram_vars:\n");
+ emit(f,".org 0x31D0\n");
+ emit(f,".equ vbcc___ram_vars_offset %d - 0x1000\n", start_ram_vars);
+ emit(f, "%s0:\n", int_handler_prefix);
+ emit(f,"\tmov\t\tx, vbcc___start_rom_vars + vbcc___ram_vars_offset\n");
+ emit(f,"\tmov\t\ty, vbcc___start_ram_vars + vbcc___ram_vars_offset\n");
+ emit(f,"\tmov\t\thl, vbcc___end_ram_vars\n");
+ emit(f,"vbcc__copy_vars_loop:\n");
+ emit(f,"\tmov\t\ta,[x]\n");
+ emit(f,"\tmov\t\t[y],a\n");
+ emit(f,"\tinc\t\tx\n");
+ emit(f,"\tinc\t\ty\n");
+ emit(f,"\tcmp\t\thl, y\n");
+ emit(f,"\tjnz\t\tvbcc__copy_vars_loop\n");
+ emit(f,"\tmovw\tsp, 0x2000\n");
+ emit(f,"\tmovw\tnn, 0x2000\n");
+ emit(f,"\tmovb\t[nn+0x21], 0x0C\n");
+ emit(f,"\tmovb\t[nn+0x25], (1<<7)\n");
+ emit(f,"\tmovb\tflags, 0\n");
+ emit(f,"\tmovb\t[nn+0x80], 0b00001000\n");
+ emit(f,"\tmovb\t[nn+0x81], 0b00001001\n");
+ emit(f,"\tcall\tmain\n");
+ emit(f,"vbcc___infinite_loop:\n");
+ emit(f,"\tjmp\tvbcc___infinite_loop\n");
+}
diff --git a/machines/pm/machine.c b/machines/pm/machine.c
new file mode 100755
index 0000000..81ca077
--- /dev/null
+++ b/machines/pm/machine.c
@@ -0,0 +1,1412 @@
+
+#include "supp.h"
+
+
+static debug_prints = 0;
+
+static char FILE_[]=__FILE__;
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for Pokemon Mini V0.019 (c) in 2011 by zoranc";
+
+
+/* Commandline-flags the code-generator accepts:
+ 0: just a flag
+ VALFLAG: a value must be specified
+ STRINGFLAG: a string can be specified
+ FUNCFLAG: a function will be called
+ apart from FUNCFLAG, all other versions can only be specified once */
+int g_flags[MAXGF]= { FUNCFLAG, STRINGFLAG, STRINGFLAG, STRINGFLAG };
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+ they collide with the frontend */
+char *g_flags_name[MAXGF] = { "h", "ram-vars", "id", "name" };
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+#define HELP_DUMP (g_flags[0]&USEDFLAG)
+#define RAM_VARS_ADDR ((g_flags[1]&USEDFLAG)?address_number(g_flags_val[1].p):0x14E0)
+#define GAME_ID ((g_flags[2]&USEDFLAG)?g_flags_val[2].p:"PKCC")
+#define GAME_NAME ((g_flags[3]&USEDFLAG)?g_flags_val[3].p:"PokeCCbyZC")
+
+
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* Sizes of all elementary types in bytes. */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* CHAR_BIT of the target machine. */
+zmax char_bit;
+
+/* Names of all registers. */
+char *regnames[]={"noreg","x","y", "ba", "hl"};
+char *regnames_low[]={"noreg","noreg","noreg", "a", "l"};
+char *regnames_high[]={"noreg","noreg","noreg", "b", "h"};
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* Type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1]={0,1,1};
+
+
+/****************************************/
+/* Some private data and functions. */
+/****************************************/
+
+static long malign[MAX_TYPE+1]= {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+static long msizetab[MAX_TYPE+1]={0,1,1,2,4,4,4,8,8,0,2,0,0,0,2,0};
+
+struct Typ ityp={SHORT},ltyp={LONG};
+
+static int ix = 1,iy = 2;
+static int q1reg,q2reg,zreg;
+static int ba = 3,hl = 4; /* temporary gprs */
+
+
+/* return-instruction */
+static char *ret;
+
+static char *marray[]={"__POKEMINI__",0};
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+#define ISLWORD(t) ((t&NQ)==LONG||(t&NQ)==FLOAT)
+#define ISHWORD(t) ((t&NQ)==INT)
+
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="vbcc___l",*idprefix="";
+
+/* has to be 4 bytes long */
+static char game_id[10] = "PKCC";
+/* can be up to 12 bytes long */
+static char game_name[20] = "PokeCCbyZC";
+
+static void emit_irq_vectors(FILE *f);
+static void emit_unised_irq_labels(FILE *f);
+static int used_interrupt[26];
+static char *int_handler_prefix="vbcc___interrupt_handler_";
+
+static int start_ram_vars = 0x14E0;
+static int ram_rom_distance = 0x11D0;
+static int end_ram_vars;
+static int last_was_rom = 1;
+static int ram_vars_initialized = 0;
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__interrupt", "__rom", "__align8", "__align64", 0};
+#define INTERRUPT 1
+#define ROM 2
+#define ALIGN8 4
+#define ALIGN64 8
+
+#include "emit.h"
+
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+
+//static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *ccs2[]={"nz","z","ge","l","g","le",""};
+//static char *uccs2[]={"nzb","zb","ge","l","g","le",""};
+static char *uccs2[]={"nz","z","nc","c","c","nc",""};
+//static char *uccs2[]={"nzb","zb","no","o","ns","s",""};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+static long localsize, rsavesize, /*argsize,*/ pushed;
+
+#define NOT_IMP() not_implemented((f),(__LINE__))
+void not_implemented(FILE *f, int line)
+{
+ emit(f, ";\tNOT IMPLEMENTED: %s LINE: %d !!!\n", __FILE__, line);
+}
+
+/* calculate the actual current offset of an object relativ to the
+ stack-pointer; we use a layout like this:
+ ------------------------------------------------
+ | arguments to this function |
+ ------------------------------------------------
+ | return-address [size=3] |
+ ------------------------------------------------
+ | caller-save registers [size=rsavesize] |
+ ------------------------------------------------
+ | local variables [size=localsize] |
+ ------------------------------------------------
+ | arguments to called functions [size=argsize] |
+ ------------------------------------------------
+ All sizes will be aligned as necessary.
+ In the case of FIXED_SP, the stack-pointer will be adjusted at
+ function-entry to leave enough space for the arguments and have it
+ aligned to 16 bytes. Therefore, when calling a function, the
+ stack-pointer is always aligned to 16 bytes.
+ For a moving stack-pointer, the stack-pointer will usually point
+ to the bottom of the area for local variables, but will move while
+ arguments are put on the stack.
+
+ This is just an example layout. Other layouts are also possible.
+ */
+
+static long real_offset(struct obj *o)
+{
+ long off=zm2l(o->v->offset);
+
+ if(off<0){
+ /* function parameter */
+ off=localsize+rsavesize+3-off-zm2l(maxalign);
+ }
+
+ off+=pushed;
+
+ off+=zm2l(o->val.vmax);
+
+ return off;
+}
+
+static void emit_irq_vectors(FILE *f)
+{
+ int i;
+ for(i=0; i<26; i++)
+ {
+ emit(f, ".orgfill 0x%x\n", 0x2102 + 6 * i);
+ emit(f, "\tjmp\t%s%d\n", int_handler_prefix, i);
+ }
+
+ used_interrupt[0] = 1;
+}
+
+static void emit_unised_irq_labels(FILE *f)
+{
+ int i;
+ for(i=0; i<26; i++)
+ {
+ if(!used_interrupt[i])
+ emit(f, "%s%d:\n", int_handler_prefix, i);
+ }
+}
+
+char *flags_verbose(int flags, char *str)
+{
+ static char *flag_str[] = {"KONST", "VAR", "", "", "", "DREFOBJ", "REG", "VARADR"};
+ int i;
+
+ strcpy(str, "");
+
+ for(i=0; i<8; i++)
+ {
+ if(flags & (1 << i))
+ {
+ if(strlen(str)!=0 && strlen(flag_str[i])!=0)
+ strcat(str, "|");
+ strcat(str, flag_str[i]);
+ }
+ }
+
+ return str;
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/* Generates code to load the address of a variable into register r. */
+{
+ char str[100];
+ if(debug_prints)
+ emit(f, ";\tload_address(reg:%s, flags:%s, type:%s)\n", regnames[r], flags_verbose(o->flags, str), typname[type&NQ]);
+ if(!(o->flags&VAR)) ierror(0);
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER)
+ {
+ long off=real_offset(o);
+ emit(f,"\tmov\t%s,sp\n",regnames[r]);
+ if(off)
+ emit(f,"\tadd\t%s,%ld\n",regnames[r],off);
+ }
+ else
+ {
+ emit(f,"\tmov\t%s,",regnames[r]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }
+}
+/* Generates code to load a memory object into register r. tmp is a
+ general purpose register which may be used. tmp can be r. */
+static void load_reg(FILE *f, int r, struct obj *o, int type, int type2)
+{
+ char str[100];
+ if(debug_prints)
+ emit(f, ";\tload_reg(reg:%s, flags:%s, type:%s, type2:%s)\n", regnames[r], flags_verbose(o->flags, str), typname[type&NQ], (type2&NQ)?typname[type2&NQ]:"");
+ type&=NU;
+ if(o->flags&VARADR)
+ {
+ load_address(f,r,o,POINTER);
+ }
+ else
+ {
+ if((o->flags&(REG|DREFOBJ))==REG&&o->reg==r)
+ return;
+ if( msizetab[(type&NQ)] == 1 &&
+ !((o->flags==VAR) /*&& (o->v->storage_class==AUTO||o->v->storage_class==REGISTER)*/))
+ {
+ /* TODO */
+ /* optimise this like in the store_reg() */
+ int is_16_reg = ((o->flags&(REG|DREFOBJ)) == REG) && msizetab[type2&NQ] == 2;
+ if(r == ba || r == hl)
+ {
+ /* handle case of transfer 16-bit reg -> 8-bit reg*/
+ emit(f,"\tmov\t%s,",is_16_reg?regnames[r]:regnames_low[r]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }
+ else if(r==ix && ((o->flags&(REG|DREFOBJ)) == REG))
+ {
+ if(!is_16_reg)
+ emit(f, "\tmov\t%s, 0\n", regnames_high[o->reg]); // or maybe expand sign?
+ emit(f, "\tmov\tx,");
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }
+ else
+ NOT_IMP();
+ }
+ else
+ {
+ if((o->flags==VAR) && type==ARRAY)
+ {
+ emit(f,"\tmov\t%s,",regnames[r]);
+ o->flags |= VARADR;
+ emit_obj(f,o,type);
+ o->flags &= ~VARADR;
+ emit(f,"\n");
+ }
+ else
+ {
+ emit(f,"\tmov\t%s,",regnames[r]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }
+ }
+ }
+}
+
+static int free_index_reg()
+{
+ if(!regs[ix]) return ix;
+ if(!regs[iy]) return iy;
+ return 0;
+}
+
+/* Generates code to store register r into memory object o. */
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+ char str[100];
+ if(debug_prints)
+ emit(f, ";\tstore_reg(reg:%s, flags:%s, type:%s)\n", regnames[r], flags_verbose(o->flags, str), typname[type&NQ]);
+ type&=NQ;
+ if( msizetab[(type&NQ)] == 1 )
+ {
+ if(r == ba)
+ {
+ if((o->flags==VAR) && (o->v->storage_class==AUTO||o->v->storage_class==REGISTER))
+ {
+ int ind_reg = free_index_reg();
+ long off = real_offset(o);
+
+ if(off == 0)
+ {
+ emit(f, "\tinc\tsp\n");
+ emit(f, "\tpush\ta\n");
+ }
+ else if(ind_reg)
+ {
+ emit(f, "\tmov\t%s,sp\n", regnames[ind_reg]);
+ emit(f, "\tmov\t[%s+%ld],%s\n", regnames[ind_reg], off, regnames_low[r]);
+ }
+ else
+ {
+ emit(f,"\tmov\thl,sp\n");
+ emit(f,"\tadd\thl,%ld\n",off);
+ emit(f,"\tmov\t[hl],%s\n", regnames_low[r]);
+ }
+ }
+ else
+ {
+ emit(f,"\tmov\t");
+ emit_obj(f,o,type);
+ emit(f,",%s\n",regnames_low[r]);
+ }
+ }
+ else if(r==ix && (o->flags==VAR))
+ {
+ emit(f, "\tmov\thl,");
+ emit_obj(f,o,type);
+ emit(f, "\n");
+ emit(f, "\tmov\th, 0\n"); // maybe extend sign?
+ emit(f, "\tmov\tx,hl\n");
+ }
+ else
+ NOT_IMP();
+ }
+ else
+ {
+ emit(f,"\tmov\t");
+ emit_obj(f,o,type);
+ emit(f,",%s\n",regnames[r]);
+ }
+}
+
+
+/* Does some pre-processing like fetching operands from memory to
+ registers etc. */
+static struct IC *preload(FILE *f,struct IC *p)
+{
+ int r;
+
+ if(debug_prints)
+ emit(f, ";\tpreload() - start\n");
+
+ if(isreg(q1))
+ q1reg=p->q1.reg;
+ else
+ q1reg=0;
+
+ if(isreg(q2))
+ q2reg=p->q2.reg;
+ else
+ q2reg=0;
+
+ if(isreg(z) && ADD <= p->code && p->code <= SUB)
+ {
+ zreg=p->z.reg;
+ }
+ else
+ {
+ /*
+ if(ISFLOAT(ztyp(p)))
+ zreg=f1;
+ else
+ */
+ zreg=ba;
+ }
+ if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am)
+ {
+ if(debug_prints)
+ emit(f, ";\tpreload() - q1\n");
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,hl,&p->q1,POINTER,0);
+ p->q1.reg=hl;
+ p->q1.flags|=(REG|DREFOBJ);
+ p->q1.flags&=~KONST;
+ }
+ if(p->q1.flags/* &&LOAD_STORE */&&!isreg(q1))
+ {
+ if(debug_prints)
+ emit(f, ";\tpreload() - q1a\n");
+ /*
+ if(ISFLOAT(q1typ(p)))
+ q1reg=f1;
+ else
+ */
+ q1reg=ba;
+ load_reg(f,q1reg,&p->q1,q1typ(p),0);
+ p->q1.reg=q1reg;
+ p->q1.flags=REG;
+ }
+
+ if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am)
+ {
+ if(debug_prints)
+ emit(f, ";\tpreload() - q2\n");
+ p->q2.flags&=~DREFOBJ;
+ load_reg(f,hl,&p->q2,POINTER, 0);
+ p->q2.reg=hl;
+ p->q2.flags|=(REG|DREFOBJ);
+ p->q1.flags&=~KONST;
+ }
+ if(p->q2.flags/* &&LOAD_STORE */&&!isreg(q2))
+ {
+ if(debug_prints)
+ emit(f, ";\tpreload() - q2a\n");
+ /*
+ if(ISFLOAT(q2typ(p)))
+ q2reg=f2;
+ else
+ */
+ q2reg=hl;
+ load_reg(f,q2reg,&p->q2,q2typ(p), 0);
+ p->q2.reg=q2reg;
+ p->q2.flags=REG;
+ }
+
+ if(debug_prints)
+ emit(f, ";\tpreload() - end\n");
+
+ return p;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+ char str[100];
+ if(debug_prints)
+ emit(f, ";\tsave_result(flags:%s)\n", flags_verbose(p->z.flags, str));
+ if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
+ p->z.flags&=~DREFOBJ;
+ load_reg(f,hl,&p->z,POINTER, 0);
+ p->z.reg=hl;
+ p->z.flags|=(REG|DREFOBJ);
+ p->z.flags&=~KONST;
+ }
+ if(isreg(z)){
+ if(p->z.reg!=zreg)
+ emit(f,"\tmov\t%s,%s\n",regnames[p->z.reg],regnames[zreg]);
+ }else{
+ store_reg(f,zreg,&p->z,ztyp(p));
+ }
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+ /*
+ if(p->am){
+ if(p->am->flags&GPR_IND) emit(f,"(%s,%s)",regnames[p->am->offset],regnames[p->am->base]);
+ if(p->am->flags&IMM_IND) emit(f,"(%ld,%s)",p->am->offset,regnames[p->am->base]);
+ return;
+ }
+ */
+ if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ))
+ {
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if((p->flags&DREFOBJ)||(p->flags&(VAR|VARADR))==VAR) emit(f,"[");
+ if(p->flags®)
+ {
+ emit(f,"%s",regnames[p->reg]);
+ }
+ else if(p->flags&VAR)
+ {
+ //emit(f,"{%d,%d}", p->v->storage_class, p->flags);
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+ emit(f,"sp+%ld",real_offset(p));
+ else
+ {
+ //emit(f,"[");
+ if(!zmeqto(l2zm(0L),p->val.vmax))
+ {
+ emitval(f,&p->val,LONG);
+ emit(f,"+");
+ }
+ if(p->v->storage_class==STATIC)
+ {
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }
+ else
+ {
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ //emit(f,"]");
+ }
+ }
+ if(p->flags&KONST)
+ {
+ emitval(f,&p->val,t&NU);
+ }
+ if((p->flags&DREFOBJ)||(p->flags&(VAR|VARADR))==VAR) emit(f,"]");
+}
+
+/* Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+
+/* emit a logical instruction */
+static void emit_logical(FILE *f, int c, struct obj *q, int t)
+{
+ if(zreg==ba)
+ {
+ emit(f, "\tpush\t%s\n", regnames[q->reg]);
+ emit(f, "\tmov\thl,sp\n");
+ emit(f, "\t%s\ta,[hl]\n", logicals[c-OR]);
+ emit(f, "\txchg\ta,b\n");
+ emit(f, "\tinc\thl\n");
+ emit(f, "\t%s\ta,[hl]\n", logicals[c-OR]);
+ emit(f, "\txchg\ta,b\n");
+ emit(f, "\tpop\t%s\n", regnames[q->reg]);
+ }
+ else
+ {
+ NOT_IMP();
+ emit(f,";\t%s\t%s,",logicals[c-OR],regnames[zreg]);
+ emit_obj(f,q,t);
+ emit(f,"\n");
+ }
+}
+
+/* emit a shift instruction */
+static void emit_shift(FILE *f, int c, struct obj *q, int t)
+{
+ int l1, l2, l3;
+ l1 = ++label;
+ l2 = ++label;
+ l3 = ++label;
+ if(zreg==ba)
+ {
+ emit(f, "\tcmp\t%s,16\n",regnames[q->reg]);
+ emit(f, "\tjc\t%s%d\n",labprefix,l1);
+ if(c == RSHIFT && !(t&UNSIGNED))
+ emit(f, "\tmov\tba,0xffff\n");
+ else
+ emit(f, "\tmov\tba, 0\n");
+ emit(f, "\tjmp\t%s%d\n",labprefix,l3);
+ emit(f, "%s%d:\n",labprefix,l1);
+ emit(f, "\tcmp\t%s,0\n",regnames[q->reg]);
+ emit(f, "\tjz\t%s%d\n",labprefix,l3);
+ emit(f, "%s%d:\n",labprefix,l2);
+ if(c == LSHIFT)
+ {
+ emit(f, "\tshl\ta\n");
+ emit(f, "\trolc\tb\n");
+ }
+ else
+ {
+ if (t&UNSIGNED)
+ emit(f, "\tshr\tb\n");
+ else
+ emit(f, "\tsar\tb\n");
+ emit(f, "\trorc\ta\n");
+ }
+ emit(f, "\tdec\t%s\n", regnames[q->reg]);
+ emit(f, "\tjnz\t%s%d\n",labprefix,l2);
+ emit(f, "%s%d:\n",labprefix,l3);
+ }
+ else
+ {
+ NOT_IMP();
+ emit(f,";\t%s\t%s,", arithmetics[c-LSHIFT], regnames[zreg]);
+ emit_obj(f,q,t);
+ emit(f,"\n");
+ }
+}
+static void emit_move_array(FILE *f, struct obj *z, struct obj *q, int size)
+{
+ int l1;
+ l1 = ++label;
+ emit(f,"\tmov\thl,%d\n", size);
+ if(regs[ix])
+ {
+ pushed+=2;
+ emit(f, "\tpush\tx\n");
+ }
+ if(regs[iy])
+ {
+ pushed+=2;
+ emit(f, "\tpush\ty\n");
+ }
+ load_reg(f, iy, q, POINTER, 0);
+ z->flags |= VARADR;
+ load_reg(f, ix, z, POINTER, 0);
+ z->flags &= ~VARADR;
+
+ emit(f, "%s%d:\n",labprefix,l1);
+ emit(f, "\tmov\t[x],[y]\n");
+ emit(f, "\tinc\tx\n");
+ emit(f, "\tinc\ty\n");
+ emit(f, "\tdec\thl\n");
+ emit(f, "\tjnzb\t%s%d\n",labprefix,l1);
+
+ if(regs[iy])
+ {
+ pushed-=2;
+ emit(f, "\tpop\ty\n");
+ }
+ if(regs[ix])
+ {
+ pushed-=2;
+ emit(f, "\tpop\tx\n");
+ }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+ emit(f,"\n");
+ rsavesize=0;
+ if(v->storage_class==EXTERN)
+ {
+ /*
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,";\t.global\t%s%s\n",idprefix,v->identifier);
+ */
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }
+ else
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ if(offset)
+ emit(f,"\tsub\tsp,%ld\n", offset);
+}
+
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+ if(offset)
+ emit(f,"\tadd\tsp,%ld\n", offset);
+ emit(f,ret);
+}
+
+int address_number(char *str)
+{
+ if(strncmp(str, "0x", 2)==0)
+ return strtol(str, 0, 16);
+ else
+ return atoi(str);
+}
+
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+void help(char *str)
+{
+ printf("Parameters:\n");
+ printf(" -help This help screen \n");
+ printf(" -ram-vars=<ADDR> Address from which will start ram variables. \n");
+ printf(" Default value is 0x14E0 \n");
+ printf(" -id=<ID_STR> Identificatior of the game. Maximum 4 characters long.\n");
+ printf(" -name=<NAME_STR> Name of the game. Maximum 12 characters. \n");
+ fflush(stdout);
+ exit(0);
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ return 0;
+}
+
+
+int init_cg(void)
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(1L);
+ char_bit=l2zm(8L);
+ for(i=0;i<=MAX_TYPE;i++)
+ {
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+ for(i=1;i<=MAXR;i++)
+ {
+ regsize[i]=l2zm(2L);regtype[i]=&ityp;
+ }
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=t_min[SHORT];
+ t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=t_max[SHORT];
+ t_max[LONG]=ul2zum(2147483647UL);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=tu_max[SHORT];
+ tu_max[LONG]=ul2zum(4294967295UL);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ start_ram_vars = RAM_VARS_ADDR;
+
+ memset(game_id, 0, sizeof(game_id));
+ strncpy(game_id, GAME_ID, 4);
+
+ memset(game_name, 0, sizeof(game_id));
+ strncpy(game_name, GAME_NAME, 12);
+
+ target_macros=marray;
+
+ for(i=0; i<26; i++)
+ used_interrupt[i] = 0;
+
+ return 1;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+{
+ int f=t->flags&NQ;
+ if(ISSCALAR(f)&&((f&NQ)==INT||(f&NQ)==SHORT||f==CHAR))
+ return ix;
+ return 0;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(!ISSCALAR(t)) return 0;
+ return 1;
+}
+
+int shortcut(int c,int t)
+{
+ /* TODO */
+ /* enable those for more optimised code */
+ /*if(c==COMPARE||c==AND||c==OR||c==XOR) return 1;*/
+ return 0;
+}
+
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+{
+ int op=o&NQ,tp=t&NQ;
+ if(op==tp) return 0;
+ if(ISHWORD(op)&&ISHWORD(tp)) return 0;
+ if(ISFLOAT(op)||ISFLOAT(tp)) return 1;
+ if(ISLWORD(op)&&ISLWORD(tp)) return 0;
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ /*
+ if(newobj&§ion!=SPECIAL)
+ emit(f,"%ld\n",zm2l(size));
+ else
+ emit(f,"\t.space\t%ld\n",zm2l(size));
+ newobj=0;
+ */
+ int i;
+ int num_per_line = 16;
+ for(i=0; i<size; ++i)
+ {
+ if(i % num_per_line == 0)
+ emit(f, "\t.db\t");
+ if(i % num_per_line == num_per_line - 1 || i == size - 1)
+ emit(f, "0\n");
+ else
+ emit(f, "0, ");
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ if((t&NQ)==CHAR || (t&NQ)==SHORT)
+ emit(f,"\t.db\t");
+ else if((t&NQ)==INT || (t&NQ)==POINTER)
+ emit(f,"\t.dw\t");
+ else
+ emit(f,";\tdc.%s %d\t",dt(t&NQ), t&NQ);
+
+ if(!p->tree)
+ {
+ /*
+ if(ISFLOAT(t))
+ {
+ // auch wieder nicht sehr schoen und IEEE noetig
+ unsigned char *ip;
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ if((t&NQ)!=FLOAT)
+ {
+ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ }
+ else
+ */
+ emitval(f,&p->val,t&NU);
+ if((t&NQ)==CHAR && 0x20 <= p->val.vchar && p->val.vchar <=0x7f)
+ emit(f, "\t; '%c'", (char)p->val.vchar);
+ }
+ else
+ {
+ emit_obj(f,&p->tree->o,t&NU);
+ }
+ emit(f,"\n");
+ //newobj=0;
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag = 0;
+ char *sec;
+ if(v->clist) constflag=is_const(v->vtyp);
+
+ if(v->tattr&ALIGN8)
+ {
+ emit(f, "\t.align\t8\n");
+ /*
+ emit(f, "\t.equ\tvbcc___unaligned_address .\n");
+ emit(f, "\t.equ\tvbcc___unaligned_address2 (vbcc___unaligned_address + 7)\n");
+ emit(f, "\t.equ\tvbcc___unaligned_address3 (vbcc___unaligned_address2 & 7)\n");
+ emit(f, "\t.equ\tvbcc___unaligned_address4 (vbcc___unaligned_address2 - vbcc___unaligned_address3)\n");
+ emit(f, "\t.org\tvbcc___unaligned_address4\n");
+ */
+ }
+
+ if(v->tattr&ALIGN64)
+ {
+ emit(f, "\t.align\t64\n");
+ /*
+ emit(f, "\t.equ\tvbcc___unaligned_address .\n");
+ emit(f, "\t.equ\tvbcc___unaligned_address2 (vbcc___unaligned_address + 63)\n");
+ emit(f, "\t.equ\tvbcc___unaligned_address3 (vbcc___unaligned_address2 & 63)\n");
+ emit(f, "\t.equ\tvbcc___unaligned_address4 (vbcc___unaligned_address2 - vbcc___unaligned_address3)\n");
+ emit(f, "\t.org\tvbcc___unaligned_address4\n");
+ */
+ }
+
+ if(/*(v->tattr&ROM) ||*/ /*constflag*/ is_const(v->vtyp))
+ {
+ //emit(f, "\n\t; CONST\n");
+ if(!last_was_rom)
+ {
+ emit(f, "\t.equ\tvbcc___saved_rom_shadow .\n");
+ emit(f, "\t.org\tvbcc___saved_rom_shadow - %d\n", ram_rom_distance);
+ emit(f, "\t.equ\tvbcc___saved_ram_addr .\n");
+ emit(f, "\t.org\tvbcc___saved_rom_addr\n");
+ last_was_rom = 1;
+ }
+ }
+ else
+ {
+ //emit(f, "; in ram!!! %s%ld: %s%s: \n",labprefix,zm2l(v->offset), idprefix,v->identifier);
+ if(last_was_rom)
+ {
+ emit(f, "\t.equ\tvbcc___saved_rom_addr .\n");
+ if(!ram_vars_initialized)
+ {
+ emit(f, "\t.org\t%d\n", start_ram_vars);
+ emit(f, "\t.equ\tvbcc___saved_ram_addr .\n");
+ ram_vars_initialized = 1;
+ }
+ else
+ {
+ emit(f, "\t.org\tvbcc___saved_ram_addr\n");
+ }
+ last_was_rom = 0;
+ }
+ else
+ {
+ emit(f, "\t.equ\tvbcc___saved_rom_shadow .\n");
+ emit(f, "\t.org\tvbcc___saved_rom_shadow - %d\n", ram_rom_distance);
+ emit(f, "\t.equ\tvbcc___saved_ram_addr .\n");
+ }
+ }
+
+ if(v->storage_class==STATIC)
+ {
+ if(!ISFUNC(v->vtyp->flags))
+ {
+ /*
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(v->clist||section==SPECIAL){
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }else
+ emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+ newobj=1;
+ */
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }
+ }
+ if(v->storage_class==EXTERN)
+ {
+ //emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+ if(v->flags&(DEFINED|TENTATIVE)){
+ /*
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(v->clist||section==SPECIAL){
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+ newobj=1;
+ */
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }
+ }
+ if(!last_was_rom)
+ {
+ emit(f, "\t.org\tvbcc___saved_ram_addr + %d\n", ram_rom_distance);
+ }
+}
+
+static int init_dump = 0;
+
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+{
+ int c, t, t2, i, cmp_type = 0;
+ struct IC *m;
+
+ if(!init_dump)
+ {
+ init_dump = 1;
+ emit_start(f);
+ }
+
+ if(strcmp(v->identifier,"main")==0)
+ {
+ emit_end(f);
+ }
+
+ localsize=(zm2l(offset));
+ for(m=p;m;m=m->next)
+ {
+ c=m->code;t=m->typf&NU;
+ /* convert MULT/DIV/MOD with powers of two */
+ if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+ eval_const(&m->q2.val,t);
+ i=pof2(vmax);
+ if(i){
+ if(c==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ m->code=AND;
+ }else{
+ vmax=l2zm(i-1);
+ if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+ }
+ c=m->code;
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ if(c==AND){
+ insert_const(&m->q2.val,t);
+ }else{
+ insert_const(&m->q2.val,INT);
+ m->typf2=INT;
+ }
+ }
+ }
+ //if(c==CALL&&argsize<zm2l(m->q2.val.vmax)) argsize=zm2l(m->q2.val.vmax);
+ }
+ //emit(f, ";%s\n", v->identifier);
+
+ if(v->tattr&INTERRUPT)
+ {
+ char *p;
+
+ for(p = v->identifier; *p; ++p)
+ if(isdigit(*p))
+ break;
+ if(!*p)
+ {
+ fprintf(stderr, "ERROR: Interrupt routine with no interrupt number!\n");
+ }
+ else
+ {
+ int num = atoi(p);
+ if(used_interrupt[num])
+ {
+ fprintf(stderr, "ERROR: Interrupt %d defined twice!\n", num);
+ }
+ else
+ {
+ used_interrupt[num] = 1;
+ emit(f, "%s%d:\n", int_handler_prefix, num);
+
+ emit(f, "\tpushax\n");
+ ret="\tpopax\n\treti\n";
+ }
+ }
+ }
+ else
+ ret="\tret\n";
+
+ function_top(f,v,localsize);
+ pushed=0;
+
+
+ for(;p;p=p->next)
+ {
+ if(debug_prints)
+ {
+ fprintf(f,";;;;");
+ pric2(f,p);
+ }
+
+ c=p->code;
+ t=p->typf&NU;
+ t2=p->typf2&NU;
+
+ if(c==ALLOCREG)
+ {
+ regs[p->q1.reg]=1;
+ continue;
+ }
+ if(c==FREEREG)
+ {
+ regs[p->q1.reg]=0;
+ continue;
+ }
+ if(c==BRA){
+ /*
+ if(t==exit_label)
+ emit(f,ret);
+ else
+ */
+ emit(f,"\tjmp\t%s%d\n",labprefix,t);
+ continue;
+ }
+ if(c>=BEQ&&c<BRA){
+ int tmp_label = ++label;
+ /* FIXME */
+ /* some of the comparissions can be also 16-bit jumps */
+ if(debug_prints)
+ emit(f, "; t: 0x%x (0x%x) so: ", cmp_type, UNSIGNED);
+ if(cmp_type&UNSIGNED)
+ {
+ if(debug_prints)
+ emit(f, "UNSIGNED\n");
+ if(c < BLE)
+ {
+ emit(f,"\tj%s\t%s%d\n",uccs2[c-BEQ],labprefix,tmp_label);
+ emit(f,"\tjmp\t%s%d\n",labprefix,t);
+ }
+ else
+ {
+ if(c==BLE)
+ {
+ emit(f,"\tjz\t%s%d\n",labprefix,t);
+ emit(f,"\tj%s\t%s%d\n",uccs2[c-BEQ],labprefix,t);
+ }
+ else /* BGT */
+ {
+ emit(f,"\tjz\t%s%d\n",labprefix,tmp_label);
+ emit(f,"\tj%s\t%s%d\n",uccs2[c-BEQ],labprefix,t);
+ }
+ }
+ }
+ else
+ {
+ if(debug_prints)
+ emit(f, "SIGNED\n");
+ emit(f,"\tj%s\t%s%d\n",ccs2[c-BEQ],labprefix,tmp_label);
+ emit(f,"\tjmp\t%s%d\n",labprefix,t);
+ }
+ emit(f,"%s%d:\n",labprefix,tmp_label);
+ continue;
+ }
+ if(c==MOVETOREG){
+ load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags, 0);
+ continue;
+ }
+ if(c==MOVEFROMREG){
+ store_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+ continue;
+ }
+ if(c==CALL){
+ if((p->q1.flags & (VAR|DREFOBJ)) == VAR &&
+ p->q1.v->fi &&
+ p->q1.v->fi->inline_asm)
+ {
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ }
+ else
+ {
+ emit(f,"\tcall\t");
+ if(p->q1.v->storage_class==STATIC)
+ {
+ emit(f,"%s%ld",labprefix,zm2l(p->q1.v->offset));
+ }
+ else
+ {
+ emit(f,"%s%s",idprefix,p->q1.v->identifier);
+ }
+ emit(f,"\n");
+ }
+ if(pushed != 0)
+ emit(f,"\tadd\tsp,%ld\n", pushed);
+ pushed = 0;
+ continue;
+ }
+
+ if(c==ADDRESS)
+ {
+ if(isreg(z))
+ zreg=p->z.reg;
+ else
+ zreg=ba;
+ load_address(f,zreg,&p->q1,POINTER);
+ save_result(f,p);
+ continue;
+ }
+
+ p=preload(f,p);
+ c=p->code;
+
+ if(c==SUBPFP) c=SUB;
+ if(c==ADDI2P) c=ADD;
+ if(c==SUBIFP) c=SUB;
+
+ if(c==CONVERT)
+ {
+ /* FIXME */
+ if(ISFLOAT(q1typ(p))||ISFLOAT(ztyp(p))) ierror(0);
+ load_reg(f,zreg,&p->q1,t, t2);
+ if(sizetab[q1typ(p)&NQ]<sizetab[ztyp(p)&NQ] && (ztyp(p)&NQ&POINTER)!=POINTER)
+ {
+ if(zreg == ba && msizetab[q1typ(p)&NQ] == 1)
+ {
+ if(q1typ(p)&UNSIGNED)
+ emit(f,"\tmov\tb,0\n");
+ else
+ emit(f,"\tex\tba,a\n",dt(q1typ(p)),regnames[zreg]);
+ }
+ else
+ NOT_IMP();
+ }
+ save_result(f,p);
+ continue;
+ }
+
+ if(c==SETRETURN){
+ load_reg(f,p->z.reg,&p->q1,t, 0);
+ continue;
+ }
+
+ if(c==GETRETURN){
+ if(p->q1.reg){
+ zreg=p->q1.reg;
+ save_result(f,p);
+ }else
+ p->z.flags=0;
+ continue;
+ }
+
+ if(c==ASSIGN)
+ {
+ if(debug_prints)
+ emit(f,"; ASSIGN start\n");
+ if(t==0)
+ ierror(0);
+ if(t==ARRAY)
+ {
+ emit_move_array(f, &p->z, &p->q1, p->q2.val.vmax);
+ }
+ else
+ {
+ load_reg(f,zreg,&p->q1,t, 0);
+ save_result(f,p);
+ }
+ if(debug_prints)
+ emit(f,"; ASSIGN end\n");
+ continue;
+ }
+
+ if(c==PUSH)
+ {
+ if(t==0) ierror(0);
+ pushed+=zm2l(p->q2.val.vmax);
+ //emit(f,"\tmov\t[sp+%ld],",pushed);
+ emit(f, "\tpush\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ continue;
+ }
+
+ if(c==LABEL)
+ {
+ emit(f,"%s%d:\n",labprefix,t);
+ continue;
+ }
+
+ if(c==KOMPLEMENT)
+ {
+ load_reg(f,ba,&p->q1,t, 0);
+ emit(f,"\tnot\ta\n");
+ emit(f,"\tnot\tb\n");
+ save_result(f,p);
+ continue;
+ }
+
+ if(c==MINUS)
+ {
+ load_reg(f,ba,&p->q1,t, 0);
+ emit(f,"\tmov\thl,0\n");
+ emit(f,"\tsub\thl,ba\n");
+ emit(f,"\tmov\tba,hl\n");
+ save_result(f,p);
+ continue;
+ }
+
+ if(c==TEST)
+ {
+ if(q1reg != ba)
+ {
+ emit(f, "\tmov\tba,");
+ emit_obj(f,&p->q1,t);
+ emit(f, "\n");
+ }
+ emit(f,"\tcmp\t%s,0\n", (msizetab[(t&NQ)]==1)?"a":"ba");
+ continue;
+ }
+
+ if(c==COMPARE)
+ {
+ cmp_type = t;
+ if(q1reg != ba)
+ {
+ emit(f, "\tmov\tba,");
+ emit_obj(f,&p->q1,t);
+ emit(f, "\n");
+ }
+ emit(f,"\tcmp\t%s,", (msizetab[(t&NQ)]==1)?"a":"ba");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ continue;
+ }
+
+ if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD))
+ {
+ load_reg(f, zreg, &p->q1, t, 0);
+ if(c>=OR&&c<=AND)
+ {
+ emit_logical(f, c, &p->q2, t);
+ }
+ else if(c>=LSHIFT&&c<=RSHIFT)
+ {
+ emit_shift(f, c, &p->q2, t);
+ }
+ else if(c==MULT)
+ {
+ load_reg(f, ba, &p->q1, t, 0);
+ load_reg(f, hl, &p->q2, t, 0);
+ emit(f, "\tcall\tvbcc___mul16x16_16\n");
+ }
+ else if(DIV <=c && c <=MOD)
+ {
+ load_reg(f, ba, &p->q1, t, 0);
+ load_reg(f, hl, &p->q2, t, 0);
+ emit(f, "\tcall\tvbcc___div_mod16x16_16\n");
+ if(c==MOD)
+ emit(f, "\tmov\tba, hl\n");
+ }
+ else
+ {
+ if(zreg != ba)
+ emit(f, "\tmov\tba,%s\n", regnames[zreg]);
+ emit(f,"\t%s\t%s,",arithmetics[c-LSHIFT],regnames[ba]);
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ if(zreg != ba)
+ emit(f, "\tmov\t%s,ba\n", regnames[zreg]);
+ }
+ save_result(f,p);
+ continue;
+ }
+
+ fprintf(f,";\tNOT IMPLEMENTED INSTRUCTION >>> %s <<< (code:%d)\n", ename[p->code], p->code);
+ fprintf(f,";;;;");
+ pric2(f,p);
+ }
+
+ function_bottom(f,v,localsize);
+}
+
+void cleanup_cg(FILE *f)
+{
+}
+
+void init_db(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+}
diff --git a/machines/pm/machine.dt b/machines/pm/machine.dt
new file mode 100755
index 0000000..0926f51
--- /dev/null
+++ b/machines/pm/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S16BUbE S16BULE
+
+
diff --git a/machines/pm/machine.h b/machines/pm/machine.h
new file mode 100755
index 0000000..2b4bec6
--- /dev/null
+++ b/machines/pm/machine.h
@@ -0,0 +1,55 @@
+
+
+#include "dt.h"
+
+
+
+/* The number of registers of the target machine. */
+#define MAXR 2
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 4
+
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P INT
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 0
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 1
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 1
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 20000 /* should be enough */
+
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 1
+
+/* We have asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES
diff --git a/machines/ppc/machine.c b/machines/ppc/machine.c
new file mode 100644
index 0000000..e547fc1
--- /dev/null
+++ b/machines/ppc/machine.c
@@ -0,0 +1,4012 @@
+/* Code generator for a PPC RISC cpu with 32 general purpose, */
+/* 32 floating point and 8 condition code registers. */
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+#include "dwarf2.c"
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for PPC V0.7 (c) in 1997-2022 by Volker Barthelmann";
+
+/* Commandline-flags the code-generator accepts */
+int g_flags[MAXGF]={STRINGFLAG,STRINGFLAG,0,0,0,0,
+ 0,0,0,0,0,
+ 0,0,0,0,0,0,
+ 0,0,0};
+char *g_flags_name[MAXGF]={"cpu","fpu","const-in-data","sd","merge-constants","fsub-zero",
+ "elf","amiga-align","no-regnames","no-peephole","setccs",
+ "use-lmw","poweropen","sc","madd","eabi","gas",
+ "no-align-args","conservative-sr","use-commons",
+ "baserel32os4","baserel32mos","oldlibcalls"};
+union ppi g_flags_val[MAXGF];
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* Tabelle fuer die Groesse der einzelnen Typen */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. */
+char *regnames[MAXR+1]={"noreg",
+ "r0","r1","r2","r3","r4","r5","r6","r7",
+ "r8","r9","r10","r11","r12","r13","r14","r15",
+ "r16","r17","r18","r19","r20","r21","r22","r23",
+ "r24","r25","r26","r27","r28","r29","r30","r31",
+ "f0","f1","f2","f3","f4","f5","f6","f7",
+ "f8","f9","f10","f11","f12","f13","f14","f15",
+ "f16","f17","f18","f19","f20","f21","f22","f23",
+ "f24","f25","f26","f27","f28","f29","f30","f31",
+ "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7",
+ "cnt",
+ "r3/r4","r5/r6","r7/r8","r9/r10",
+ "r14/r15","r16/r17","r18/r19","r20/r21",
+ "r22/r23","r24/r25","r26/r27","r28/r29","r30/r31",
+ "lr"};
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* Type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1]={0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,0,0,0,1,1,1,1,
+ 1,1,1,1,
+ 0,0,0,0,0,0,0,0,0};
+
+int reg_prio[MAXR+1]={0,0,0,0,19,20,21,22,23,24,25,26,27,28,0,1,2,
+ 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,0,0,0,1,1,1,1,
+ 19,21,23,25,
+ 1,3,5,7,9,11,13,15,17};
+
+struct reg_handle empty_reg_handle={0,0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__far","__near","__chip","__saveds","__rfi","__saveall",
+ "__syscall","__nosave","__brel",0};
+#define FAR 1
+#define NEAR 2
+#define CHIP 4
+#define SAVEDS 8
+#define RFI 16
+#define SAVEALL 32
+#define SYSCALL 64
+#define NOSAVE 128
+#define BREL 256
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+#define SMALLDATA (g_flags[3]&USEDFLAG)
+#define POWEROPEN (g_flags[12]&USEDFLAG)
+#define STORMC (g_flags[13]&USEDFLAG)
+#define EABI (g_flags[15]&USEDFLAG)
+#define GAS (g_flags[16]&USEDFLAG)
+#define NOALIGNARGS (g_flags[17]&USEDFLAG)
+#define CONSERVATIVE_SR (g_flags[18]&USEDFLAG)
+#define USE_COMMONS (g_flags[19]&USEDFLAG)
+#define BASERELOS4 (g_flags[20]&USEDFLAG)
+#define BASERELMOS (g_flags[21]&USEDFLAG)
+#define OLDLIBCALLS (g_flags[22]&USEDFLAG)
+
+
+static char *mregnames[MAXR+1];
+
+static char *ret="\tblr\n";
+
+static long malign[MAX_TYPE+1]= {1,1,2,4,4,8,4,8,8,1,4,1,1,1,4,1};
+static long msizetab[MAX_TYPE+1]={1,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
+
+static struct Typ ltyp={LONG},lltyp={LLONG},ldbl={DOUBLE},lchar={CHAR};
+
+static char *marray[]={"__section(x,y)=__vattr(\"section(\"#x\",\"#y\")\")",
+ "__PPC__",
+ "__aos4libcall=__attr(\"aos4libcall;\")",
+ "__linearvarargs=__attr(\"linearvarargs;\")",
+ "__interrupt=__rfi __saveall",
+ 0};
+
+const int r4=5,r5=6,r6=7,r3r4=74,r5r6=75;
+
+
+static int r0=1; /* special register */
+static int r2=3; /* reserved or toc */
+static int r3=4; /* return value */
+static int sp=2; /* Stackpointer */
+static int fp=2; /* Framepointer */
+static int vlafp=32; /* Framepointer to use with vlas */
+static int sd=14; /* SmallDataPointer */
+static int sd2=3; /* SmallData2 (eabi) */
+static int t1=12,t2=13,t3=1; /* Temporaries used by code generator */
+static int f1=45,f2=46,f3=33; /* Temporaries used by code generator */
+static int cr0=65; /* Default condition-code-register */
+static int ctr=73; /* ctr */
+static int lr=87; /* link register */
+static int bp32os4=3; /* baserel32 pointer for Amiga OS4 */
+static int bp32mos=14; /* baserel32 pointer for MorphOS */
+
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define TOC 4
+#define SDATA 5
+#define SDATA2 6
+#define SBSS 7
+#define SPECIAL 8
+
+#if HAVE_OSEK
+/* removed */
+/* removed */
+#endif
+
+static long stack;
+static int stack_valid;
+static long tmpoff; /* offset for additional temporaries, upper end! */
+static int lastlabel,exit_label;
+static int sdp;
+static int q1loaded,q2loaded;
+static int section=-1,newobj,crsave;
+static char *codename="\t.text\n\t.align\t2\n",
+ *dataname="\t.data\n\t.align\t2\n",
+ *bssname="",
+ *rodataname="\t.section\t.rodata\n\t.align\t2\n",
+ *tocname="\t.tocd\n\t.align\t2\n",
+ *sdataname="\t.section\t\".sdata\",\"aw\"\n\t.align\t2\n",
+ *sdata2name="\t.section\t\".sdata2\",\"a\"\n\t.align\t2\n",
+ *sbssname="\t.section\t\".sbss\",\"auw\"\n\t.align\t2\n";
+
+static char *labprefix="l",*idprefix="_",*tocprefix="@_";
+static long frameoffset,pushed,maxpushed,framesize,localoffset,minframe=8;
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+static int all_regs;
+
+struct StatFPtrList {
+ struct StatFPtrList *next;
+ struct Var *vptr;
+};
+static struct StatFPtrList *firstfptr = NULL;
+
+void title(FILE *f)
+{
+ static int done;
+ extern char *inname; /*grmpf*/
+ if(!done&&f){
+ done=1;
+ emit(f,"\t.file\t\"%s\"\n",inname);
+ }
+}
+
+static long real_offset(struct obj *o)
+{
+ long off;
+ if(zm2l(o->v->offset)>=0){
+ return zm2l(o->v->offset)+frameoffset+zm2l(o->val.vmax);
+ }else{
+ return framesize+minframe-zm2l(o->v->offset)-zm2l(maxalign)+zm2l(o->val.vmax);
+ }
+}
+static long hi(long off)
+{
+ zmax zm=l2zm(off),r=zmrshift(zm,l2zm(16L));
+ if(!zmeqto(zmand(zm,l2zm(32768L)),l2zm(0L))) r=zmadd(r,l2zm(1L));
+ return zm2l(zs2zm(zm2zs(zmand(r,l2zm(65535L)))));
+}
+static long lo(long off)
+{
+ return zm2l(zs2zm(zm2zs(zmand(l2zm(off),l2zm(65535L)))));
+}
+static struct fpconstlist {
+ struct fpconstlist *next;
+ int label,typ;
+ union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+ struct fpconstlist *p=firstfpc;
+ t&=NQ;
+ if(t==LDOUBLE) t=DOUBLE;
+ if(g_flags[4]&USEDFLAG){
+ for(p=firstfpc;p;p=p->next){
+ if(t==p->typ){
+ eval_const(&p->val,t);
+ if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+ if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+ }
+ }
+ }
+ p=mymalloc(sizeof(struct fpconstlist));
+ p->next=firstfpc;
+ p->label=++label;
+ p->typ=t;
+ p->val=o->val;
+ firstfpc=p;
+ return p->label;
+}
+
+#define REG_IND 1
+#define IMM_IND 2
+#define UPDATE 64
+
+static struct obj *cam(int flags,int base,long offset)
+/* Initializes an addressing-mode structure and returns a pointer to */
+/* that object. Will not survive a second call! */
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ am.offset=offset;
+ return &obj;
+}
+
+static char *ldts[]={"","bz","ha","wz","wz","wz","fs","fd","fd","","wz"};
+static char *ldtu[]={"","bz","hz","wz","wz","wz","??","??","??","??","??"};
+static char *sdts[]={"","b","h","w","w","w","fs","fd","fd","","w"};
+static char *sdtu[]={"","b","h","w","w","w","??","??","??","??","??"};
+
+#define ldt(t) ((t&UNSIGNED)?ldtu[t&NQ]:ldts[t&NQ])
+#define sdt(t) ((t&UNSIGNED)?sdtu[t&NQ]:sdts[t&NQ])
+
+static int special_section(FILE *f,struct Var *v)
+{
+ char *sec;
+ if(!v->vattr) return 0;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return 0;
+ sec+=strlen("section(");
+ emit(f,"\t.section\t");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+static int use_sd(int t)
+/* Shall the object of type t be addressed in small-data-mode? */
+{
+ int r=0;
+ if(ISFUNC(t)) return 0;
+ if(g_flags[3]&USEDFLAG)
+ r=sd;
+ else if(STORMC&&(t&NQ)<=POINTER)
+ r=sd;
+ else if(EABI&&ISSCALAR(t)){
+ if(t&CONST)
+ r=sd2;
+ else
+ r=sd;
+ }
+ return r;
+}
+
+static void load_address(FILE *f,int r,struct obj *o,int typ)
+/* Generates code to load the address of a variable into register r. */
+{
+ BSET(regs_modified,r);
+ if(!(o->flags&VAR))
+ ierror(0);
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+ long off=real_offset(o);
+ if(off<=32767){
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[r],mregnames[fp],off);
+ }else{
+ if(r==r0){
+ BSET(regs_modified,t2);
+ emit(f,"\taddis\t%s,%s,%ld\n",mregnames[t2],mregnames[fp],hi(off));
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[r],mregnames[t2],lo(off));
+ }else{
+ emit(f,"\taddis\t%s,%s,%ld\n",mregnames[r],mregnames[fp],hi(off));
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[r],mregnames[r],lo(off));
+ }
+ }
+ }else{
+ if((sdp=use_sd(o->v->vtyp->flags))&&!(o->v->tattr&FAR)
+ &&zmleq(l2zm(0L),o->val.vmax)&&!zmleq(szof(o->v->vtyp),o->val.vmax)){
+ emit(f,"\tla\t%s,",mregnames[r]);
+ emit_obj(f,o,typ);
+ if(GAS)
+ emit(f,"@sda21(0)\n");
+ else
+ emit(f,"(%s)\n",mregnames[sdp]);
+ }else{
+ if(POWEROPEN){
+ zmax offset=o->val.vmax;
+ if(f){
+ if((o->v->vtyp->flags&NQ)==FUNKT&&o->v->storage_class==STATIC){
+ /* check if static function pointer was already created in TOC */
+ struct StatFPtrList **oldsfp=&firstfptr;
+ struct StatFPtrList *sfp=firstfptr;
+ while(sfp){
+ if(sfp->vptr==o->v) break;
+ oldsfp=&sfp->next;
+ sfp=sfp->next;
+ }
+ if(!sfp){
+ *oldsfp=sfp=mymalloc(sizeof(struct StatFPtrList));
+ sfp->next=NULL;
+ sfp->vptr=o->v;
+ }
+ }
+ emit(f,"\tl%s\t%s,%s",ldt(LONG),mregnames[r],tocprefix);
+ o->val.vmax=l2zm(0L);emit_obj(f,o,POINTER);o->val.vmax=offset;
+ emit(f,"(%s)\n",mregnames[r2]);
+ if(hi(zm2l(offset))) emit(f,"\taddis\t%s,%s,%ld\n",mregnames[r],mregnames[r],hi(zm2l(offset)));
+ if(lo(zm2l(offset))) emit(f,"\taddi\t%s,%s,%ld\n",mregnames[r],mregnames[r],lo(zm2l(offset)));
+ }
+ }else{
+ if(BASERELOS4){
+ emit(f,"\taddis\t%s,%s,",mregnames[r],mregnames[bp32os4]);
+ emit_obj(f,o,typ);emit(f,"@brel@ha\n");
+ emit(f,"\taddi\t%s,%s,",mregnames[r],mregnames[r]);
+ emit_obj(f,o,typ);emit(f,"@brel@l\n");
+ }else if(BASERELMOS){
+ emit(f,"\taddis\t%s,%s,",mregnames[r],mregnames[bp32mos]);
+ emit_obj(f,o,typ);emit(f,"@drel@ha\n");
+ emit(f,"\taddi\t%s,%s,",mregnames[r],mregnames[r]);
+ emit_obj(f,o,typ);emit(f,"@drel@l\n");
+ }else{
+ emit(f,"\tlis\t%s,",mregnames[r]);
+ emit_obj(f,o,typ);emit(f,"@ha\n");
+ emit(f,"\taddi\t%s,%s,",mregnames[r],mregnames[r]);
+ emit_obj(f,o,typ);emit(f,"@l\n");
+ }
+ }
+ }
+ }
+}
+static void load_reg(FILE *f,int r,struct obj *o,int typ,int tmp)
+/* Generates code to load a memory object into register r. tmp is a */
+/* general purpose register which may be used. tmp can be r. */
+{
+ typ&=NU;
+ BSET(regs_modified,r);
+ if(o->flags&KONST){
+ long l;
+ eval_const(&o->val,typ);
+ if(ISFLOAT(typ)){
+ int lab;
+ if((g_flags[5]&USEDFLAG)&&zldeqto(vldouble,d2zld(0.0))){
+ emit(f,"\tfsub\t%s,%s,%s\n",mregnames[r],mregnames[r],mregnames[r]);
+ return;
+ }
+ lab=addfpconst(o,typ);
+ if(sdp=use_sd(typ)){
+ if(GAS)
+ emit(f,"\tl%s\t%s,%s%d@sda21(0)\n",ldt(typ),mregnames[r],labprefix,lab);
+ else
+ emit(f,"\tl%s\t%s,%s%d(%s)\n",ldt(typ),mregnames[r],labprefix,lab,mregnames[sdp]);
+ }else{
+ BSET(regs_modified,tmp);
+ if(POWEROPEN){
+ emit(f,"\tl%s\t%s,%s%s%ld(%s)\n",ldt(LONG),mregnames[tmp],tocprefix,labprefix,(long)lab,mregnames[r2]);
+ emit(f,"\tl%s\t%s,0(%s)\n",ldt(typ),mregnames[r],mregnames[tmp]);
+ }else{
+ emit(f,"\tlis\t%s,%s%d@ha\n",mregnames[tmp],labprefix,lab);
+ emit(f,"\tl%s\t%s,%s%d@l(%s)\n",ldt(typ),mregnames[r],labprefix,lab,mregnames[tmp]);
+ }
+ }
+ return;
+ }
+ if(r==1) ierror(0);
+ l=hi(zm2l(vmax));
+ if(l){
+ emit(f,"\tlis\t%s,%ld\n",mregnames[r],l);
+ l=lo(zm2l(vmax));
+ if(l)
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[r],mregnames[r],l);
+ }else{
+ emit(f,"\tli\t%s,%ld\n",mregnames[r],lo(vmax));
+ }
+ return;
+ }
+ if((o->flags&VAR)&&(o->v->storage_class==EXTERN||o->v->storage_class==STATIC)){
+ if(o->flags&VARADR){
+ load_address(f,r,o,POINTER);
+ }else{
+ if((sdp=use_sd(o->v->vtyp->flags))&&!(o->v->tattr&FAR)){
+ emit(f,"\tl%s\t%s,",ldt(typ),mregnames[r]);
+ emit_obj(f,o,typ);
+ if(GAS)
+ emit(f,"@sda21(0)\n");
+ else
+ emit(f,"(%s)\n",mregnames[sdp]);
+ }else{
+ BSET(regs_modified,tmp);
+ if(POWEROPEN){
+ zmax offset=o->val.vmax;
+ emit(f,"\tl%s\t%s,%s",ldt(LONG),mregnames[tmp],tocprefix);
+ o->val.vmax=l2zm(0L);emit_obj(f,o,POINTER);o->val.vmax=offset;
+ emit(f,"(%s)\n",mregnames[r2]);
+ if(hi(zm2l(offset))) emit(f,"\taddis\t%s,%s,%ld\n",mregnames[tmp],mregnames[tmp],hi(zm2l(offset)));
+ emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(typ),mregnames[r],lo(zm2l(offset)),mregnames[tmp]);
+ }else{
+ if(BASERELOS4){
+ emit(f,"\taddis\t%s,%s,",mregnames[tmp],mregnames[bp32os4]);
+ emit_obj(f,o,typ);emit(f,"@brel@ha\n");
+ emit(f,"\tl%s\t%s,",ldt(typ),mregnames[r]);
+ emit_obj(f,o,typ);emit(f,"@brel@l(%s)\n",mregnames[tmp]);
+ }else if(BASERELMOS){
+ emit(f,"\taddis\t%s,%s,",mregnames[tmp],mregnames[bp32mos]);
+ emit_obj(f,o,typ);emit(f,"@drel@ha\n");
+ emit(f,"\tl%s\t%s,",ldt(typ),mregnames[r]);
+ emit_obj(f,o,typ);emit(f,"@drel@l(%s)\n",mregnames[tmp]);
+ }else{
+ emit(f,"\tlis\t%s,",mregnames[tmp]);
+ emit_obj(f,o,typ);emit(f,"@ha\n");
+ emit(f,"\tl%s\t%s,",ldt(typ),mregnames[r]);
+ emit_obj(f,o,typ);emit(f,"@l(%s)\n",mregnames[tmp]);
+ }
+ }
+ }
+ }
+ }else{
+ if((o->flags&(DREFOBJ|REG))==REG){
+ if(r!=o->reg)
+ emit(f,"\t%smr\t%s,%s\n",r>=33?"f":"",mregnames[r],mregnames[o->reg]);
+ }else if(!o->am&&(o->flags&(DREFOBJ|REG))==(REG|DREFOBJ)){
+ emit(f,"\tl%s\t%s,0(%s)\n",ldt(typ),mregnames[r],mregnames[o->reg]);
+ }else if(!o->am){
+ long off=real_offset(o);
+ if(off<=32767){
+ emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(typ),mregnames[r],off,mregnames[fp]);
+ }else{
+ BSET(regs_modified,tmp);
+ emit(f,"\taddis\t%s,%s,%ld\n",mregnames[tmp],mregnames[fp],hi(off));
+ emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(typ),mregnames[r],lo(zm2l(off)),mregnames[tmp]);
+ }
+ }else{
+ emit(f,"\tl%s%s%s\t%s,",ldt(typ),(o->am->flags&UPDATE)?"u":"",(o->am->flags®_IND)?"x":"",mregnames[r]);
+ emit_obj(f,o,typ);emit(f,"\n");
+ }
+ }
+}
+
+static void store_reg(FILE *f,int r,struct obj *o,int typ)
+/* Generates code to store register r into memory object o. */
+{
+ int tmp;
+ typ&=NQ;
+ if((o->flags&VAR)&&(o->v->storage_class==EXTERN||o->v->storage_class==STATIC)){
+ int tmp=t1;
+ if(tmp==r) tmp=t2;
+ if((sdp=use_sd(o->v->vtyp->flags))&&!(o->v->tattr&FAR)){
+ emit(f,"\tst%s\t%s,",sdt(typ),mregnames[r]);
+ emit_obj(f,o,typ);
+ if(GAS)
+ emit(f,"@sda21(0)\n");
+ else
+ emit(f,"(%s)\n",mregnames[sdp]);
+ return;
+ }else{
+ BSET(regs_modified,tmp);
+ if(POWEROPEN){
+ zmax offset=o->val.vmax;
+ emit(f,"\tl%s\t%s,%s",ldt(LONG),mregnames[tmp],tocprefix);
+ o->val.vmax=l2zm(0L);emit_obj(f,o,POINTER);o->val.vmax=offset;
+ emit(f,"(%s)\n",mregnames[r2]);
+ if(hi(zm2l(offset))) emit(f,"\taddis\t%s,%s,%ld\n",mregnames[tmp],mregnames[tmp],hi(zm2l(offset)));
+ emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(typ),mregnames[r],lo(zm2l(offset)),mregnames[tmp]);
+ return;
+ }else{
+ if(BASERELOS4){
+ emit(f,"\taddis\t%s,%s,",mregnames[tmp],mregnames[bp32os4]);
+ emit_obj(f,o,typ);emit(f,"@brel@ha\n");
+ emit(f,"\tst%s\t%s,",sdt(typ),mregnames[r]);
+ emit_obj(f,o,typ);emit(f,"@brel@l(%s)\n",mregnames[tmp]);
+ }else if(BASERELMOS){
+ emit(f,"\taddis\t%s,%s,",mregnames[tmp],mregnames[bp32mos]);
+ emit_obj(f,o,typ);emit(f,"@drel@ha\n");
+ emit(f,"\tst%s\t%s,",sdt(typ),mregnames[r]);
+ emit_obj(f,o,typ);emit(f,"@drel@l(%s)\n",mregnames[tmp]);
+ }else{
+ emit(f,"\tlis\t%s,",mregnames[tmp]);
+ emit_obj(f,o,typ);emit(f,"@ha\n");
+ emit(f,"\tst%s\t%s,",sdt(typ),mregnames[r]);
+ emit_obj(f,o,typ);emit(f,"@l(%s)\n",mregnames[tmp]);
+ }
+ return;
+ }
+ }
+ }
+ if(!(o->flags&DREFOBJ)&&!o->am){
+ long off=real_offset(o);
+ if(r==t1) tmp=t2; else tmp=t1;
+ if(off<=32767){
+ emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(typ),mregnames[r],off,mregnames[fp]);
+ }else{
+
+ BSET(regs_modified,tmp);
+ emit(f,"\taddis\t%s,%s,%ld\n",mregnames[tmp],mregnames[fp],hi(off));
+ emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(typ),mregnames[r],lo(off),mregnames[tmp]);
+ }
+ }else{
+ if(!o->am){
+ emit(f,"\tst%s\t%s,",sdt(typ),mregnames[r]);
+ emit_obj(f,o,typ);emit(f,"\n");
+ }else{
+ emit(f,"\tst%s%s%s\t%s,",sdt(typ),(o->am->flags&UPDATE)?"u":"",(o->am->flags®_IND)?"x":"",mregnames[r]);
+ emit_obj(f,o,typ);emit(f,"\n");
+ }
+ }
+}
+
+static long pof2(zumax x)
+/* Yields log2(x)+1 oder 0. */
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+
+#if 1
+static char *dct[]={"","byte","2byte","4byte","4byte","4byte","4byte","4byte","4byte"};
+#else
+static char *dct[]={"","byte","short","long","long","long","long","long","long"};
+#endif
+static struct IC *do_refs(FILE *,struct IC *);
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"or","xor","and"};
+static char *record[]={"","."};
+static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
+static char *isimm[]={"","i"};
+
+static struct IC *do_refs(FILE *f,struct IC *p)
+/* Does some pre-processing like fetching operands from memory to */
+/* registers etc. */
+{
+ int typ,typ1,reg,c=abs(p->code);
+
+ q1loaded=q2loaded=0;
+
+ /* cannot use q1typ, because p->code may have been negated */
+ if(c==CONVERT)
+ typ=p->typf2;
+ else
+ typ=p->typf;
+
+ if((typ&NQ)==POINTER) typ=UNSIGNED|LONG;
+
+ if((c==SUB||c==SUBIFP)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&(typ&NQ)<=LLONG){
+ eval_const(&p->q2.val,typ);
+ if(zmleq(vmax,l2zm(32768L))&&zmleq(l2zm(-32767L),vmax)){
+ union atyps val;
+ if(c==SUB){
+ if(p->code==SUB) p->code=c=ADD; else p->code=c=-ADD;
+ }else{
+ if(p->code==SUBIFP) p->code=c=ADDI2P; else p->code=c=-ADDI2P;
+ }
+ c=abs(c);
+ val.vmax=zmsub(l2zm(0L),vmax);
+ eval_const(&val,MAXINT);
+ insert_const(&p->q2.val,typ);
+ p->typf=typ=(typ&~UNSIGNED);
+ }
+ }
+
+ q1reg=q2reg=zreg=0;
+ if(p->q1.flags®) q1reg=p->q1.reg;
+ if(p->q2.flags®) q2reg=p->q2.reg;
+ if((p->z.flags&(REG|DREFOBJ))==REG) zreg=p->z.reg;
+
+ if((p->q1.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q1.val,typ);
+ if(ISFLOAT(typ)) reg=f1; else reg=t1;
+ if(c==ASSIGN&&zreg) reg=zreg;
+ if(c==SETRETURN&&p->z.reg) reg=p->z.reg;
+ if(c!=SUB||(typ&NQ)>LONG||!zmleq(vmax,l2zm(32767L))||!zmleq(l2zm(-32768L),vmax)){
+ load_reg(f,reg,&p->q1,typ,t1);
+ q1reg=reg;
+ q1loaded=1;
+ }
+ }else if(c!=ADDRESS){
+ if(ISFLOAT(typ)) reg=f1; else reg=t1;
+ if((c==ASSIGN||(c==CONVERT&&ISINT(p->typf2)))&&zreg>=1&&zreg<=32) reg=zreg;
+ if((c==ASSIGN||(c==CONVERT&&ISFLOAT(p->typf2)))&&zreg>=33&&zreg<=64) reg=zreg;
+ if(c==SETRETURN&&p->z.reg) reg=p->z.reg;
+ if(p->q1.am){
+ load_reg(f,reg,&p->q1,typ,t1);
+ q1reg=reg;
+ q1loaded=1;
+ }else{
+ if(p->q1.flags&&!q1reg){
+ if(p->q1.flags&DREFOBJ) {typ1=POINTER;reg=t1;} else typ1=typ;
+ if((typ1&NQ)<=POINTER){
+ int m=p->q1.flags;
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,reg,&p->q1,typ1,t1);
+ p->q1.flags=m;
+ q1reg=reg;
+ q1loaded=1;
+ }
+ }
+ if((p->q1.flags&DREFOBJ)&&(typ&NQ)<=POINTER){
+ if(ISFLOAT(typ)) reg=f1; else reg=t1;
+ if((c==ASSIGN||(c==CONVERT&&ISINT(p->typf2)))&&zreg>=1&&zreg<=32) reg=zreg;
+ if((c==ASSIGN||(c==CONVERT&&ISFLOAT(p->typf2)))&&zreg>=33&&zreg<=64) reg=zreg;
+ if(c==SETRETURN&&p->z.reg) reg=p->z.reg;
+ if(p->q1.am)
+ load_reg(f,reg,&p->q1,typ,t1);
+ else
+ load_reg(f,reg,cam(IMM_IND,q1reg,0),typ,t1);
+ q1reg=reg;
+ q1loaded=1;
+ }
+ }
+ }
+ /* cannot use q2typ (see above) */
+ typ=p->typf;
+ if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,typ);
+ if(ISFLOAT(typ)) reg=f2; else reg=t2;
+ if(ISFLOAT(typ)||c==DIV||c==SUB||c==MOD){
+ load_reg(f,reg,&p->q2,typ,t2);
+ q2reg=reg;
+ q2loaded=1;
+ }else{
+ if((c>=OR&&c<=AND)||(c==COMPARE&&(typ&UNSIGNED))){
+ if(!zumleq(vumax,ul2zum(65535UL))){
+ load_reg(f,reg,&p->q2,typ,t2);
+ q2reg=reg;
+ q2loaded=1;
+ }
+ }else{
+ if(!zmleq(vmax,l2zm(32767L))||!zmleq(l2zm(-32768L),vmax)){
+ load_reg(f,reg,&p->q2,typ,t2);
+ q2reg=reg;
+ q2loaded=1;
+ }
+ }
+ }
+ }else{
+ if(p->q2.am){
+ if(ISFLOAT(typ)) reg=f2; else reg=t2;
+ load_reg(f,reg,&p->q2,typ,t2);
+ q2reg=reg;
+ q2loaded=1;
+ }else{
+ if(p->q2.flags&&!q2reg){
+ if((p->q2.flags&DREFOBJ)) typ1=POINTER; else typ1=typ;
+ if(ISFLOAT(typ1)) reg=f2; else reg=t2;
+ if((typ1&NQ)<=POINTER){
+ int m=p->q2.flags;
+ p->q2.flags&=~DREFOBJ;
+ load_reg(f,reg,&p->q2,typ1,t2);
+ p->q2.flags=m;
+ q2reg=reg;
+ q2loaded=1;
+ }
+ }
+ if((p->q2.flags&DREFOBJ)&&(typ&NQ)<=POINTER){
+ if(ISFLOAT(typ)) reg=f2; else reg=t2;
+ if(p->q2.am)
+ load_reg(f,reg,&p->q2,typ,t2);
+ else
+ load_reg(f,reg,cam(IMM_IND,q2reg,0),typ,t2);
+ q2reg=reg;
+ q2loaded=1;
+ }
+ }
+ }
+ if(p->z.am||(p->z.flags&&!isreg(z))){
+ typ=p->typf;
+ if(c!=ADDRESS&&ISFLOAT(typ)) zreg=f3; else zreg=t3;
+ }
+ if(q1reg){p->q1.flags=REG;p->q1.reg=q1reg;p->q1.am=0;}
+ if(q2reg){p->q2.flags=REG;p->q2.reg=q2reg;p->q2.am=0;}
+ return p;
+}
+static void pr(FILE *f,struct IC *p)
+ /* Writes the destination register to the real destination if necessary. */
+{
+ int typ=p->typf;
+ if(p->code==ADDRESS) typ=POINTER;
+ if(p->z.flags){
+ if(zreg>=74&&zreg<=86){printf("c=%d\n",p->code); ierror(0);}
+ if(p->z.am){
+ store_reg(f,zreg,&p->z,typ);
+ }else if(!isreg(z)){
+ if(p->z.flags&DREFOBJ){
+ if(p->z.flags®){
+ if(p->z.am)
+ store_reg(f,zreg,&p->z,typ);
+ else
+ store_reg(f,zreg,cam(IMM_IND,p->z.reg,0),typ);
+ }else{
+ int r;
+ if(t1==zreg) r=t2; else r=t1;
+ load_reg(f,r,&p->z,POINTER,r);
+ store_reg(f,zreg,cam(IMM_IND,r,0),typ);
+ }
+ }else{
+ store_reg(f,zreg,&p->z,typ);
+ }
+ }else{
+ if(p->z.reg!=zreg)
+ emit(f,"\t%smr\t%s,%s\n",(zreg>=33&&zreg<=64)?"f":"",mregnames[p->z.reg],mregnames[zreg]);
+ }
+ }
+}
+static int dwarf2_regnumber(int r)
+{
+ if(r==0) ierror(0);
+ if(r<=32)
+ return r-1;
+ else if(r<=64)
+ return r+6;
+ else
+ ierror(0);
+}
+static zmax dwarf2_fboffset(struct Var *v)
+{
+ struct obj o;
+ if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0);
+ o.flags=VAR;
+ o.v=v;
+ o.val.vmax=l2zm(0L);
+ return l2zm(real_offset(&o));
+}
+static void dwarf2_print_frame_location(FILE *f,struct Var *v)
+{
+ struct obj o;
+ o.flags=REG;
+ o.reg=sp;
+ o.val.vmax=l2zm(0L);
+ o.v=0;
+ dwarf2_print_location(f,&o);
+}
+static void emit_obj(FILE *f,struct obj *p,int t)
+/* Prints an object. */
+{
+ if(p->am){
+ if(p->am->flags®_IND) emit(f,"%s,%s",mregnames[p->am->offset],mregnames[p->am->base]);
+ if(p->am->flags&IMM_IND) emit(f,"%ld(%s)",p->am->offset,mregnames[p->am->base]);
+ return;
+ }
+ /* if(p->flags&DREFOBJ) emit(f,"(");*/
+ if(p->flags&VAR) {
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+ if(p->flags®){
+ emit(f,"%s",mregnames[p->reg]);
+ }else{
+ emit(f,"%ld(%s)",real_offset(p),mregnames[fp]);
+ }
+ }else{
+ if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,MAXINT);emit(f,"+");}
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ }
+ }
+ if((p->flags®)&&!(p->flags&VAR)) emit(f,"%s",mregnames[p->reg]);
+ if(p->flags&KONST){
+ emitval(f,&p->val,t&NU);
+ }
+ /* if(p->flags&DREFOBJ) emit(f,")");*/
+}
+static int exists_freereg(struct IC *p,int reg)
+/* Test if there is a sequence of FREEREGs containing FREEREG reg. */
+{
+ while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+ if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+ p=p->next;
+ }
+ return 0;
+}
+
+static size_t lsize;
+static bvtype *once,*twice;
+
+static void peephole(struct IC *p)
+/* Try to use addressing modes */
+{
+ int c,c2,r,cnt,maxlabel,uselr=0;struct IC *p2;struct AddressingMode *am;
+ if(cross_module){
+ lastlabel=0;
+ for(p2=p;p2;p2=p2->next){
+ if(p2->code>=LABEL&&p2->code<=BRA){
+ if(!lastlabel||p2->typf<lastlabel) lastlabel=p2->typf;
+ if(p->typf>maxlabel) maxlabel=p->typf;
+ }
+ }
+ }else{
+ maxlabel=label; /*FIXME*/
+ }
+ /*lsize=((label-lastlabel+1+7)/CHAR_BIT)*CHAR_BIT;*/
+ lsize=BVSIZE(label-lastlabel+1);
+ once=mymalloc(lsize);
+ twice=mymalloc(lsize);
+ memset(once,0,lsize);
+ memset(twice,0,lsize);
+ for(;p;p=p->next){
+ c=p->code;
+ if(c==CALL){
+ if(p->call_list==0){
+ uselr=1;
+ }else{
+ int i;
+ for(i=0;i<p->call_cnt;i++)
+ if(!p->call_list[i].v->fi||
+ !p->call_list[i].v->fi->inline_asm||
+ !(p->call_list[i].v->fi->flags&ALL_REGS)||
+ BTST(p->call_list[i].v->fi->regs_modified,lr))
+ uselr=1;
+ }
+ }
+ if((q1typ(p)&NQ)==LLONG&&(c==MULT||c==DIV||c==MOD||c==LSHIFT||c==RSHIFT)) uselr=1;
+ if(c==CONVERT&&(q1typ(p)&NQ)==LLONG&&ISFLOAT(ztyp(p)&NQ)) uselr=1;
+ if(c==CONVERT&&(ztyp(p)&NQ)==LLONG&&ISFLOAT(q1typ(p)&NQ)) uselr=1;
+ if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+ if(c==LABEL) exit_label=p->typf;
+ /* Test which labels are jumped to more than once. */
+ if((c>=BEQ&&c<=BRA)&&p->typf-lastlabel>=lsize*CHAR_BIT){
+ printf("lsize=%lu p->typf=%d lastlabel=%d\n",lsize,p->typf,lastlabel);
+ ierror(0);
+ }
+ if(c>=BEQ&&c<=BRA){
+ if(BTST(once,p->typf-lastlabel))
+ BSET(twice,p->typf-lastlabel);
+ else
+ BSET(once,p->typf-lastlabel);
+ }
+ /* Try test-opt */
+ if(c==TEST&&!(p->q1.flags&DREFOBJ)){
+ for(p2=p->prev;p2;p2=p2->prev){
+ c2=p2->code;
+ if(c2==NOP||c2==ALLOCREG||c2==FREEREG) continue;
+ if(c2==CALL||(c2>=LABEL&&c2<=BRA)) break;
+ if((p2->z.flags&DREFOBJ)&&(p->q1.flags&(REG|DREFOBJ))!=REG) break;
+ if(p->q1.flags==p2->z.flags&&p->q1.am==p2->z.am){
+ if(!(p->q1.flags&VAR)||(p->q1.v==p2->z.v&&zmeqto(p->q1.val.vmax,p2->z.val.vmax))){
+ if(!(p->q1.flags®)||p->q1.reg==p2->z.reg){
+ if(p->z.flags==0||(isreg(z)&&p->z.reg==cr0)){
+ if(p->typf==p2->typf&&(!(p->typf&UNSIGNED)||!multiple_ccs)){
+ p2->ext.setcc=1;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* Try update */
+ if((c==ADDI2P||c==SUBIFP)&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg){
+ if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+ if(zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))){
+ struct obj *o;
+ r=p->q1.reg;cnt=0;o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==NOP||c2==ALLOCREG||c2==FREEREG) continue;
+ if((c2==CALL/*&®scratch[r]*/)||(c2>=LABEL&&c2<=BRA)) break;
+ if((p2->q1.flags&(DREFOBJ|REG))==REG&&p2->q1.reg==r) break;
+ if((p2->q2.flags&(DREFOBJ|REG))==REG&&p2->q2.reg==r) break;
+ if((p2->z.flags&(DREFOBJ|REG))==REG&&p2->z.reg==r) break;
+ if((p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r) cnt|=1;
+ if((p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r) cnt|=2;
+ if((p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r) cnt|=4;
+ if((cnt&3)==3) break;
+ if(cnt){
+ if(cnt&1){
+ if((q1typ(p2)&NQ)==LLONG) break;
+ o=&p2->q1;
+ }else if(cnt&2){
+ if((q2typ(p2)&NQ)==LLONG) break;
+ o=&p2->q2;
+ }else{
+ if((ztyp(p2)&NQ)==LLONG) break;
+ o=&p2->z;
+ }
+ if(p2->code==ASSIGN&&((p2->typf&NQ)>POINTER||!zmeqto(p2->q2.val.vmax,sizetab[p2->typf&NQ])))
+ break;
+ o->am=am=mymalloc(sizeof(*am));
+ o->am->flags=(IMM_IND|UPDATE);
+ o->am->base=r;
+ o->am->offset=zm2l(vmax);
+ p->code=c=NOP;
+ break;
+ }
+ }
+ }
+ }
+ }
+ /* Try const(reg) */
+#ifndef oldpeep
+ if((c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+ int base;zmax of;struct obj *o;
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ if(zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))){
+ r=p->z.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ am->base=base;
+ am->offset=zm2l(of);
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+#else
+ if((c==ADDI2P||c==SUBIFP)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&isreg(z)){
+ int base;zmax of;
+ p2=p->next;
+ while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
+ if(p2) c2=p2->code; else c2=0;
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ r=p->z.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ if(c2&&zmleq(l2zm(-32768L),of)&&zmleq(of,l2zm(32767L))&&c2!=CALL&&(c2<LABEL||c2>BRA)
+ &&(c2!=ASSIGN||((p2->typf&NQ)<=POINTER&&zmeqto(p2->q2.val.vmax,sizetab[p2->typf&NQ])))
+ &&c2!=ADDRESS&&(((p2->z.flags&(DREFOBJ|REG))==REG&&p2->z.reg==r&&p2->q2.flags==0)||exists_freereg(p2->next,r))){
+ if(((p2->q1.flags&(REG|DREFOBJ))!=REG||p2->q1.reg!=r)
+ &&((p2->q2.flags&(REG|DREFOBJ))!=REG||p2->q2.reg!=r)){
+ cnt=0;
+ if((p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ p2->q1.am=am=mymalloc(sizeof(*am));
+ p2->q1.am->flags=IMM_IND;
+ p2->q1.am->base=base;
+ p2->q1.am->offset=zm2l(of);
+ cnt++;
+ }
+ if((p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ p2->q2.am=am=mymalloc(sizeof(*am));
+ p2->q2.am->flags=IMM_IND;
+ p2->q2.am->base=base;
+ p2->q2.am->offset=zm2l(of);
+ cnt++;
+ }
+ if((p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ p2->z.am=am=mymalloc(sizeof(*am));
+ p2->z.am->flags=IMM_IND;
+ p2->z.am->base=base;
+ p2->z.am->offset=zm2l(of);
+ cnt++;
+ }
+ if(isreg(q1)){
+ p->code=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=ASSIGN;p->q2.flags=0;
+ }
+ if(cnt==1&&((p2->q1.flags&(DREFOBJ|REG))!=REG||p2->q1.reg!=base)
+ &&((p2->q2.flags&(DREFOBJ|REG))!=REG||p2->q2.reg!=base)
+ &&((p2->z.flags&(DREFOBJ|REG))!=REG||p2->z.reg!=base) ){
+ /* Can we use update? */
+ p2=p2->next;
+ while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
+ if(p2){
+ c2=p2->code;
+ if(c2==ADDI2P||c2==SUBIFP){
+ if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==base
+ &&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==base
+ &&(p2->q2.flags&(KONST|DREFOBJ))==KONST ){
+ eval_const(&p2->q2.val,p2->typf);
+ if(c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+ if(zmeqto(vmax,of)){
+ am->flags|=UPDATE;
+ p2->code=NOP;
+ }
+ }
+ }
+ }
+ }
+ continue;
+ }
+ }
+ }
+#endif
+ /* Try reg,reg */
+#ifndef oldpeep
+ if(c==ADDI2P&&isreg(q2)&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+ int base,idx;struct obj *o;
+ r=p->z.reg;idx=p->q2.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||(q1typ(p2)&NQ)==LLONG) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||(q2typ(p2)&NQ)==LLONG) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||(ztyp(p2)&NQ)==LLONG) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=REG_IND;
+ am->base=base;
+ am->offset=idx;
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+#else
+ if(c==ADDI2P&&isreg(q2)&&isreg(z)&&p->q2.reg!=p->z.reg){
+ int base,idx;
+ p2=p->next;
+ while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
+ if(p2) c2=p2->code; else c2=0;
+ r=p->z.reg;idx=p->q2.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ if(c2&&c2!=CALL&&(c2<LABEL||c2>BRA)
+ &&(c2!=ASSIGN||((p2->typf&NQ)<=POINTER&&zmeqto(p2->q2.val.vmax,sizetab[p2->typf&NQ])))
+ &&c2!=ADDRESS&&exists_freereg(p2->next,r)){
+ if(((p2->q1.flags&(REG|DREFOBJ))!=REG||p2->q1.reg!=r)
+ &&((p2->q2.flags&(REG|DREFOBJ))!=REG||p2->q2.reg!=r) ){
+ cnt=0;
+ if((p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ p2->q1.am=am=mymalloc(sizeof(*am));
+ p2->q1.am->flags=REG_IND;
+ p2->q1.am->base=base;
+ p2->q1.am->offset=idx;
+ cnt++;
+ }
+ if((p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ p2->q2.am=am=mymalloc(sizeof(*am));
+ p2->q2.am->flags=REG_IND;
+ p2->q2.am->base=base;
+ p2->q2.am->offset=idx;
+ cnt++;
+ }
+ if((p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ p2->z.am=am=mymalloc(sizeof(*am));
+ p2->z.am->flags=REG_IND;
+ p2->z.am->base=base;
+ p2->z.am->offset=idx;
+ cnt++;
+ }
+ if(isreg(q1)){
+ p->code=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=ASSIGN;p->q2.flags=0;
+ }
+ if(cnt==1&&((p2->q1.flags&(DREFOBJ|REG))!=REG||p2->q1.reg!=base)
+ &&((p2->q2.flags&(DREFOBJ|REG))!=REG||p2->q2.reg!=base)
+ &&((p2->z.flags&(DREFOBJ|REG))!=REG||p2->z.reg!=base) ){
+ /* Can we use update? */
+ p2=p2->next;
+ while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
+ if(p2){
+ c2=p2->code;
+ if(c2==ADDI2P){
+ if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==base
+ &&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==base
+ &&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==idx){
+ am->flags|=UPDATE;
+ p2->code=NOP;
+ }
+ }
+ }
+ }
+ continue;
+ }
+ }
+ }
+#endif
+ }
+ if(!uselr) function_calls=0;
+}
+
+static void toc_entry(FILE *f,struct Var *v)
+/* Create a toc-entry. */
+{
+ if(!use_sd(v->vtyp->flags)||(v->tattr&FAR)){
+ if(v->storage_class==STATIC&&!ISFUNC(v->vtyp->flags)){
+ emit(f,tocname);
+ emit(f,"%s%s%ld:\n",tocprefix,labprefix,zm2l(v->offset));
+ emit(f,"\t.long\t%s%ld\n",labprefix,zm2l(v->offset));
+ }else{
+ if(!ISFUNC(v->vtyp->flags)){
+ emit(f,tocname);
+ emit(f,"%s%s%s:\n",tocprefix,idprefix,v->identifier);
+ emit(f,"\t.long\t%s%s\n",idprefix,v->identifier);
+ }
+ if(v->storage_class==EXTERN)
+ emit(f,"\t.global\t%s%s%s\n",tocprefix,idprefix,v->identifier);
+ }
+ if(f) section=TOC;
+ }
+}
+
+static int savereg(struct Var *v,int i)
+{
+ if(v->tattr&(SYSCALL|NOSAVE)) return 0;
+ if(vlas&&i==fp) return 1;
+ if((i==sd&&(v->tattr&SAVEDS))||(regused[i]&&!regscratch[i]&&!regsa[i])
+ ||((v->tattr&SAVEALL)&&i<=32&&(regscratch[i]||i==t1||i==t2||i==t3)&&((!v->fi)||(!(v->fi->flags&ALL_REGS))||BTST(v->fi->regs_modified,i)) ))
+ return 1;
+ return 0;
+}
+
+static int stmw,stme;
+
+static void function_top(FILE *f,struct Var *v,long offset)
+/* Generates function top. */
+{
+ int i,preg;long of;
+ if(POWEROPEN) toc_entry(f,v);
+ if(mregnames[1]!=regnames[1]) emit(f,"#vsc elf\n");
+ if(g_flags[0]&USEDFLAG) emit(f,"#vsc cpu %s\n",g_flags_val[0].p);
+ if(g_flags[1]&USEDFLAG) emit(f,"#vsc fpu %s\n",g_flags_val[1].p);
+ if(!special_section(f,v)&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(!GAS) emit(f,"\t.sdreg\t%s\n",mregnames[sd]);
+ if(!optsize) emit(f,"\t.align\t4\n");
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ frameoffset=minframe+maxpushed;
+ framesize=frameoffset+offset;
+ stme=0;
+ for(i=1;i<=64;i++){
+ if(savereg(v,i)){
+ if(i<=32) framesize+=4; else framesize+=8;
+ if(i<=32&&stme==0) stme=i;
+ }else{
+ if(i<=32) stme=0;
+ }
+ }
+ if(stme==32||!(g_flags[11]&USEDFLAG)) stme=0;
+ for(crsave=0,i=65;i<=72;i++)
+ if((regused[i]&&!regscratch[i]&&!regsa[i])) crsave=1;
+ if(crsave&&!POWEROPEN) framesize+=4;
+ if(framesize==minframe&&((v->tattr&(SYSCALL))||(function_calls==0&&!crsave))) framesize=frameoffset=0;
+ if(EABI)
+ framesize=(framesize+7)/8*8;
+ else
+ framesize=(framesize+15)/16*16;
+ stack=framesize;
+ stack_valid=1;
+ if(v->tattr&SYSCALL){
+ emit(f,"#barrier\n");
+ emit(f,"\tmtspr\t81,0\n");
+ emit(f,"#barrier\n");
+ emit(f,"\tstwu\t%s,-4(%s)\n",mregnames[t1],mregnames[sp]);
+ emit(f,"\tmflr\t%s\n",mregnames[t1]);
+ emit(f,"\tstwu\t%s,-4(%s)\n",mregnames[t1],mregnames[sp]);
+ emit(f,"\tbl\t%s__syscall_init\n",idprefix);
+ /*FIXME: das koennte man evtl. noch sparen */
+ emit(f,"\taddi\t%s,%s,-8\n",mregnames[sp],mregnames[sp]);
+ }else if(v->tattr&NOSAVE){
+ /* nothing */
+ }else if(function_calls||(stack_check&&framesize)){
+ emit(f,"\tmflr\t%s\n",mregnames[t1]);
+ BSET(regs_modified,t1);
+ }
+ if(stack_check&&framesize){
+ BSET(regs_modified,t2);
+ if(framesize<=32767){
+ emit(f,"\tli\t%s,%ld\n",mregnames[t2],framesize);
+ }else{
+ emit(f,"\tlis\t%s,%ld\n",mregnames[t2],hi(framesize));
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t2],mregnames[t2],lo(framesize));
+ }
+ emit(f,"\tbl\t%s__stack_check\n",idprefix);
+ if(!function_calls){
+ emit(f,"\tmtlr\t%s\n",mregnames[t1]);
+ BSET(regs_modified,lr);
+ }
+ }
+ if(function_calls&&!(v->tattr&(SYSCALL|NOSAVE))&&framesize>=32760){
+ if(POWEROPEN)
+ emit(f,"\tst%s\t%s,8(%s)\n",sdt(LONG),mregnames[t1],mregnames[sp]);
+ else
+ emit(f,"\tst%s\t%s,4(%s)\n",sdt(LONG),mregnames[t1],mregnames[sp]);
+ }
+ of=minframe+maxpushed+offset;
+ if(framesize!=0){
+ if(framesize<=32767){
+ emit(f,"\tstwu\t%s,-%ld(%s)\n",mregnames[sp],framesize,mregnames[sp]);
+ preg=sp;
+ }else{
+ BSET(regs_modified,t1);
+ BSET(regs_modified,t2);
+ emit(f,"\tmr\t%s,%s\n",mregnames[t2],mregnames[sp]);
+ emit(f,"\tlis\t%s,%ld\n",mregnames[t1],hi(-framesize));
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t1],mregnames[t1],lo(-framesize));
+ emit(f,"\tstwux\t%s,%s,%s\n",mregnames[sp],mregnames[sp],mregnames[t1]);
+ preg=t2;of-=framesize;
+ }
+ }
+ if(crsave&&!(v->tattr&NOSAVE)){
+ BSET(regs_modified,t3);
+ if(POWEROPEN){
+ emit(f,"\tmfcr\t%s\n\tst%s\t%s,4(%s)\n",mregnames[t3],sdt(LONG),mregnames[t3],mregnames[preg]);
+ }else{
+ emit(f,"\tmfcr\t%s\n\tst%s\t%s,%ld(%s)\n",mregnames[t3],sdt(LONG),mregnames[t3],of,mregnames[preg]);
+ of+=4;
+ }
+ }
+ for(i=1;i<=64;i++){
+ if(savereg(v,i)){
+ if(i<=32){
+ if(i==stme){
+ emit(f,"\tstmw\t%s,%ld(%s)\n",mregnames[stme],of,mregnames[preg]);
+ of+=(32-stme+1)*4;
+ i=32;
+ }else{
+ emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(LONG),mregnames[i],of,mregnames[preg]);
+ of+=4;
+ }
+ }else{
+ emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(DOUBLE),mregnames[i],of,mregnames[preg]);
+ of+=8;
+ }
+ }
+ }
+ if(function_calls&&!(v->tattr&(SYSCALL|NOSAVE))&&framesize<32760){
+ if(POWEROPEN)
+ emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(LONG),mregnames[t1],framesize+8,mregnames[sp]);
+ else
+ emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(LONG),mregnames[t1],framesize+4,mregnames[sp]);
+ }
+ if((v->tattr&SAVEDS)&&(SMALLDATA||BASERELMOS||POWEROPEN)){
+ if(POWEROPEN){
+ emit(f,"\t.global\t%s__getr2\n",idprefix);
+ if(!function_calls)
+ emit(f,"\tmflr\t%s\n",mregnames[t2]);
+ emit(f,"\tbl\t%s__getr2\n",idprefix);
+ if(!function_calls){
+ emit(f,"\tmtlr\t%s\n",mregnames[t2]);
+ BSET(regs_modified,lr);
+ }
+ }else{
+ if(BASERELMOS){
+ emit(f,"\t.global\t%s__restore_r13\n",idprefix);
+ emit(f,"\tbl\t%s__restore_r13\n",idprefix);
+ }else{
+ emit(f,"\tlis\t%s,%s_SDA_BASE_@ha\n",mregnames[sd],idprefix);
+ emit(f,"\taddi\t%s,%s,%s_SDA_BASE_@l\n",mregnames[sd],mregnames[sd],idprefix);
+ }
+ }
+ }
+ if(v->tattr&BREL){
+ if(BASERELOS4){
+ emit(f,"\t.global\t%s__baserel_get_addr\n",idprefix);
+ emit(f,"\tbl\t%s__baserel_get_addr\n",idprefix);
+ }
+ }
+ if(vlas){
+ emit(f,"\tmr\t%s,%s\n",mregnames[fp],mregnames[sp]);
+ emit(f,"\t.set\t____fo,%ld\n",frameoffset);
+ }
+}
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/* Generates function bottom. */
+{
+ int i,preg;long of;
+ if(v->tattr&SYSCALL){
+ emit(f,"\tb\t%s__dispatch\n",idprefix);
+ }else{
+ of=minframe+maxpushed+offset;
+ if(framesize<=32767){
+ preg=sp;
+ }else{
+ emit(f,"\tlwz\t%s,0(%s)\n",mregnames[t2],mregnames[sp]);
+ preg=t2;of-=framesize;
+ }
+ if(crsave&&!(v->tattr&NOSAVE)){
+ if(POWEROPEN){
+ emit(f,"\tl%s\t%s,8(%s)\n\tmtcr\t%s\n",ldt(LONG),mregnames[t1],mregnames[preg],mregnames[t1]);
+ }else{
+ emit(f,"\tl%s\t%s,%ld(%s)\n\tmtcr\t%s\n",ldt(LONG),mregnames[t1],of,mregnames[preg],mregnames[t1]);
+ of+=4;
+ }
+ }
+ if(function_calls&&!(v->tattr&NOSAVE)&&framesize<32760){
+ BSET(regs_modified,lr);
+ if(POWEROPEN)
+ emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(LONG),mregnames[t1],framesize+8,mregnames[sp]);
+ else
+ emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(LONG),mregnames[t1],framesize+4,mregnames[sp]);
+ }
+ for(i=1;i<=64;i++){
+ if(savereg(v,i)){
+ if(i<=32){
+ if(i==stme){
+ emit(f,"\tlmw\t%s,%ld(%s)\n",mregnames[stme],of,mregnames[preg]);
+ of+=(32-stme+1)*4;
+ i=32;
+ }else{
+ emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(LONG),mregnames[i],of,mregnames[preg]);
+ of+=4;
+ }
+ }else{
+ emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(DOUBLE),mregnames[i],of,mregnames[preg]);
+ of+=8;
+ }
+ }
+ }
+ if(framesize){
+ if(framesize<=32767)
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[sp],mregnames[sp],framesize);
+ else
+ emit(f,"\tmr\t%s,%s\n",mregnames[sp],mregnames[preg]);
+ }
+ if(function_calls&&!(v->tattr&NOSAVE)){
+ if(framesize<32760){
+ emit(f,"\tmtlr\t%s\n",mregnames[t1]);
+ }else{
+ BSET(regs_modified,lr);
+ if(POWEROPEN)
+ emit(f,"\tl%s\t%s,8(%s)\n\tmtlr\t%s\n",ldt(LONG),mregnames[t1],mregnames[sp],mregnames[t1]);
+ else
+ emit(f,"\tl%s\t%s,4(%s)\n\tmtlr\t%s\n",ldt(LONG),mregnames[t1],mregnames[sp],mregnames[t1]);
+ }
+ }
+ emit(f,ret);
+ }
+ if(v->storage_class==EXTERN){
+ emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+ emit(f,"\t.size\t%s%s,$-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
+ }else{
+ emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset));
+ emit(f,"\t.size\t%s%ld,$-%s%ld\n",labprefix,zm2l(v->offset),labprefix,zm2l(v->offset));
+ }
+ if(all_regs&&v->fi) v->fi->flags|=ALL_REGS;
+}
+
+static int balign(struct obj *o)
+/* Liefert die unteren 2 Bits des Objekts. 1 wenn unklar. */
+{
+ int sc;
+ if(o->flags&DREFOBJ) return 1;
+ if(o->am) ierror(0);
+ if(!(o->flags&VAR)) ierror(0);
+ sc=o->v->storage_class;
+ if(sc==EXTERN||sc==STATIC){
+ /* Alle statischen Daten werden vom cg auf 32bit alignt. */
+ return zm2l(zmand(o->val.vmax,l2zm(3L)));
+ }
+ if(sc==AUTO||sc==REGISTER){
+ zmax of=o->v->offset;
+ if(!zmleq(l2zm(0L),of))
+ of=zmsub(l2zm(0L),zmadd(of,maxalign));
+ return zm2l(zmand(zmadd(of,o->val.vmax),l2zm(3L)));
+ }
+ ierror(0);
+}
+
+/* load hiword of a long long object */
+static void load_hword(FILE *f,int r,struct obj *o,int t,int tmp)
+{
+ struct rpair rp;
+ BSET(regs_modified,r);
+ if(o->flags&KONST){
+ static struct obj cobj;
+ cobj.flags=KONST;
+ eval_const(&o->val,t);
+ vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff));
+ cobj.val.vulong=zum2zul(vumax);
+ load_reg(f,r,&cobj,UNSIGNED|LONG,tmp);
+ }else if(!o->am&&(o->flags&DREFOBJ)){
+ if(!(o->flags®)) ierror(0);
+ emit(f,"\tlwz\t%s,0(%s)\n",mregnames[r],mregnames[o->reg]);
+ }else if(!o->am&&(o->flags®)){
+ struct rpair rp;
+ if(!reg_pair(o->reg,&rp))
+ ierror(0);
+ if(rp.r1!=r)
+ emit(f,"\tmr\t%s,%s\n",mregnames[r],mregnames[rp.r1]);
+ }else{
+ load_reg(f,r,o,UNSIGNED|LONG,tmp);
+ }
+}
+
+/* load loword of a long long object */
+static void load_lword(FILE *f,int r,struct obj *o,int t,int tmp)
+{
+ struct rpair rp;
+ BSET(regs_modified,r);
+ if(o->flags&KONST){
+ static struct obj cobj;
+ cobj.flags=KONST;
+ eval_const(&o->val,t);
+ vumax=zumand(vumax,ul2zum(0xffffffff));
+ cobj.val.vulong=zum2zul(vumax);
+ load_reg(f,r,&cobj,UNSIGNED|LONG,tmp);
+ }else if(o->am){
+ if(o->am->flags!=IMM_IND) ierror(0);
+ o->am->offset+=4;
+ load_reg(f,r,o,UNSIGNED|LONG,tmp);
+ o->am->offset-=4;
+ }else if(o->flags&DREFOBJ){
+ if(!(o->flags®)) ierror(0);
+ emit(f,"\tlwz\t%s,4(%s)\n",mregnames[r],mregnames[o->reg]);
+ }else if(o->flags®){
+ if(!reg_pair(o->reg,&rp)) ierror(0);
+ if(rp.r2!=r)
+ emit(f,"\tmr\t%s,%s\n",mregnames[r],mregnames[rp.r2]);
+ }else{
+ o->val.vmax=zmadd(o->val.vmax,l2zm(4L));
+ load_reg(f,r,o,UNSIGNED|LONG,tmp);
+ o->val.vmax=zmsub(o->val.vmax,l2zm(4L));
+ }
+}
+/* store hiword of a long long object */
+static void store_hword(FILE *f,int r,struct obj *o)
+{
+ struct rpair rp;
+ if(!o->am&&(o->flags&DREFOBJ)){
+ if(!(o->flags®)) ierror(0);
+ emit(f,"\tstw\t%s,0(%s)\n",mregnames[r],mregnames[o->reg]);
+ }else if(!o->am&&(o->flags®)){
+ if(!reg_pair(o->reg,&rp)) ierror(0);
+ if(rp.r1!=r)
+ emit(f,"\tmr\t%s,%s\n",mregnames[rp.r1],mregnames[r]);
+ }else{
+ store_reg(f,r,o,UNSIGNED|LONG);
+ }
+}
+
+/* store loword of a long long object */
+static void store_lword(FILE *f,int r,struct obj *o)
+{
+ struct rpair rp;
+ if(o->am){
+ if(o->am->flags!=IMM_IND) ierror(0);
+ o->am->offset+=4;
+ store_reg(f,r,o,UNSIGNED|LONG);
+ o->am->offset-=4;
+ }else if(o->flags&DREFOBJ){
+ if(!(o->flags®)) ierror(0);
+ emit(f,"\tstw\t%s,4(%s)\n",mregnames[r],mregnames[o->reg]);
+ }else if(o->flags®){
+ if(!reg_pair(o->reg,&rp)) ierror(0);
+ if(rp.r2!=r)
+ emit(f,"\tmr\t%s,%s\n",mregnames[rp.r2],mregnames[r]);
+ }else{
+ o->val.vmax=zmadd(o->val.vmax,l2zm(4L));
+ store_reg(f,r,o,UNSIGNED|LONG);
+ o->val.vmax=zmsub(o->val.vmax,l2zm(4L));
+ }
+}
+/* if object cannot be dereferenced with a single load, load its address
+ in register r (!=r0) and modify the object */
+static void create_loadable(FILE *f,struct obj *o,int r)
+{
+ struct rpair rp;
+ if(o->am) return;
+ if((o->flags&(REG|DREFOBJ))==DREFOBJ){
+ o->flags&=~DREFOBJ;
+ load_reg(f,r,o,POINTER,r);
+ o->flags|=(REG|DREFOBJ);
+ o->reg=r;
+ }
+ if((o->flags&(VAR|REG))==VAR){
+ if((o->v->storage_class==STATIC||o->v->storage_class==EXTERN)&&(!use_sd(o->v->vtyp->flags)||(o->v->tattr&FAR))){
+ load_address(f,r,o,POINTER);
+ o->reg=r;
+ o->flags=(REG|DREFOBJ);
+ }
+ if((o->v->storage_class==AUTO||o->v->storage_class==REGISTER)&&real_offset(o)>32760){
+ load_address(f,r,o,POINTER);
+ o->reg=r;
+ o->flags=(REG|DREFOBJ);
+ }
+ }
+}
+
+static int get_reg()
+{
+ int i;
+ for(i=2;i<=32;i++){
+ if(!regs[i]&&(regscratch[i]||regused[i]))
+ break;
+ }
+ if(i<=32){
+ BSET(regs_modified,i);
+ return i;
+ }
+ return 0;
+}
+
+static int handle_llong(FILE *f,struct IC *p)
+{
+ int c=p->code,t,savemask=0;char *libfuncname;
+ int msp;long mtmpoff;
+
+ t=(ztyp(p)&NU);
+
+ if(c==ADDRESS) return 0;
+
+
+ if(c==GETRETURN){
+ create_loadable(f,&p->z,t1);
+ if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+ store_hword(f,rp.r1,&p->z);
+ store_lword(f,rp.r2,&p->z);
+ p->z.flags=0;
+ return 1;
+ }
+
+ if(c==SETRETURN){
+ create_loadable(f,&p->q1,t1);
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ load_hword(f,rp.r1,&p->q1,q1typ(p),t2);
+ load_lword(f,rp.r2,&p->q1,q1typ(p),t2);
+ p->z.flags=0;
+ return 1;
+ }
+
+ if(c==CONVERT&&(q1typ(p)&NQ)==LLONG&&(ztyp(p)&NQ)==LLONG){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[LLONG];
+ }
+
+ if(c==ASSIGN||c==PUSH){
+ int r;
+ create_loadable(f,&p->q1,t1);
+ if(c==ASSIGN){
+ create_loadable(f,&p->z,t2);
+ }else{
+ pushed=(pushed+3)/4*4;
+ if(align_arguments)
+ pushed=(pushed+7)/8*8;
+ }
+ if(isreg(z)){
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ load_hword(f,rp.r1,&p->q1,q1typ(p),t1);
+ }else{
+ if(isreg(q1)){
+ if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+ r=rp.r1;
+ }else{
+ if(p->q1.flags&KONST)
+ r=t1;
+ else
+ r=t3;
+ load_hword(f,r,&p->q1,q1typ(p),t1);
+ }
+ if(c==ASSIGN){
+ store_hword(f,r,&p->z);
+ }else{
+ emit(f,"\tstw\t%s,%ld(%s)\n",mregnames[r],pushed+minframe,mregnames[sp]);
+ pushed+=4;
+ }
+ }
+ if(isreg(z)){
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ load_lword(f,rp.r2,&p->q1,q1typ(p),t1);
+ }else{
+ if(isreg(q1)){
+ if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+ r=rp.r2;
+ }else{
+ if(p->q1.flags&KONST)
+ r=t1;
+ else
+ r=t3;
+ load_lword(f,r,&p->q1,q1typ(p),t1);
+ }
+ if(c==ASSIGN){
+ store_lword(f,r,&p->z);
+ }else{
+ emit(f,"\tstw\t%s,%ld(%s)\n",mregnames[r],pushed+minframe,mregnames[sp]);
+ pushed+=4;
+ }
+ }
+ p->z.flags=0;
+ return 1;
+ }
+
+ if(c==CONVERT&&(t&NQ)<LLONG){
+ if(isreg(q1)){
+ if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+ zreg=rp.r2;
+ }else{
+ int r;
+ if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==DREFOBJ)
+ create_loadable(f,&p->q1,t1);
+ if(isreg(z))
+ r=p->z.reg;
+ else
+ r=t1;
+ load_lword(f,r,&p->q1,q1typ(p),t2);
+ zreg=r;
+ }
+ return 1;
+ }
+ if(c==CONVERT&&(q1typ(p)&NQ)<LLONG){
+ int zl,zh,told=q1typ(p);
+ if(isreg(z)){
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ zh=rp.r1;
+ zl=rp.r2;
+ }else{
+ zl=t2;
+ zh=t3;
+ }
+ if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==DREFOBJ)
+ create_loadable(f,&p->q1,t1);
+ load_reg(f,zl,&p->q1,q1typ(p),t1);
+ if(told&UNSIGNED){
+ if((told&NQ)==CHAR)
+ emit(f,"\tclrlwi\t%s,%s,24\n",mregnames[zl],mregnames[zl]);
+ if((told&NQ)==SHORT)
+ emit(f,"\tclrlwi\t%s,%s,16\n",mregnames[zl],mregnames[zl]);
+ emit(f,"\tli\t%s,0\n",mregnames[zh]);
+ }else{
+ if((told&NQ)==CHAR)
+ emit(f,"\textsb\t%s,%s\n",mregnames[zl],mregnames[zl]);
+ if((told&NQ)==SHORT)
+ emit(f,"\textsh\t%s,%s\n",mregnames[zl],mregnames[zl]);
+ emit(f,"\tsrawi\t%s,%s,31\n",mregnames[zh],mregnames[zl]);
+ }
+ create_loadable(f,&p->z,t1);
+ store_lword(f,zl,&p->z);
+ store_hword(f,zh,&p->z);
+ p->z.flags=0;
+ return 1;
+ }
+
+ if(c==TEST){
+ p->code=c=COMPARE;
+ if(p->typf&UNSIGNED)
+ p->q2.val.vullong=zum2zull(ul2zum(0UL));
+ else
+ p->q2.val.vllong=zm2zll(l2zm(0L));
+ p->q2.flags=KONST;
+ }
+
+ if(c==KOMPLEMENT){
+ p->code=c=XOR;
+ p->q2.flags=KONST;
+ if(p->typf&UNSIGNED)
+ p->q2.val.vullong=tu_max[LLONG];
+ else
+ p->q2.val.vllong=l2zm(-1L);
+ }
+ if(c==MINUS){
+ p->code=c=SUB;
+ p->q2=p->q1;
+ p->q1.flags=KONST;
+ p->q1.am=0;
+ if(p->typf&UNSIGNED)
+ p->q1.val.vullong=ul2zum(0UL);
+ else
+ p->q1.val.vllong=l2zm(0L);
+ }
+
+ switch_IC(p);
+
+ if(c==COMPARE){
+ int l1,l2,h1,h2,tmp,falselab=++label,c;
+ zumax lo,uhi;zmax shi;
+ char *sh;
+ struct IC *b;
+ if(multiple_ccs)
+ ierror(0); /* still needed? */
+ else
+ p->z.reg=cr0;
+ b=p->next;
+ while(b->code==ALLOCREG||b->code==FREEREG) b=b->next;
+ c=b->code;
+ if(c<BEQ||c>BGT) ierror(0);
+ if(p->typf&UNSIGNED)
+ sh="cmplw";
+ else
+ sh="cmpw";
+ if((c==BNE||c==BEQ)&&(p->q2.flags&KONST)&&p->z.reg==cr0){
+ eval_const(&p->q2.val,q2typ(p));
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))){
+ if(isreg(q1)){
+ if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+ emit(f,"\tor.\t%s,%s,%s\n",mregnames[t1],mregnames[rp.r1],mregnames[rp.r2]);
+ }else{
+ create_loadable(f,&p->q1,t1);
+ load_lword(f,t3,&p->q1,q1typ(p),t2);
+ load_hword(f,t1,&p->q1,q1typ(p),t2);
+ emit(f,"\tor.\t%s,%s,%s\n",mregnames[t3],mregnames[t3],mregnames[t1]);
+ }
+ return 1;
+ }
+ }
+ h1=h2=l1=l2=0;
+ if(isreg(q1)){
+ if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+ h1=rp.r1;
+ l1=rp.r2;
+ }else{
+ create_loadable(f,&p->q1,t1);
+ h1=l1=t3;
+ }
+ if(isreg(q2)){
+ if(!reg_pair(p->q2.reg,&rp)) ierror(0);
+ h2=rp.r1;
+ l2=rp.r2;
+ }else if(p->q2.flags&KONST){
+ eval_const(&p->q2.val,q2typ(p));
+ lo=zumrshift(zumlshift(vumax,ul2zum(32UL)),ul2zum(32UL));
+ if(zumleq(lo,ul2zum(65535L)))
+ l2=-1;
+ if(p->typf&UNSIGNED){
+ uhi=zumrshift(vumax,ul2zum(32UL));
+ if(zumleq(uhi,ul2zum(65535L)))
+ h2=-1;
+ }else{
+ shi=zmrshift(vmax,l2zm(32L));
+ if(zmleq(shi,l2zm(32767L))&&zmleq(l2zm(-32768L),shi))
+ h2=-1;
+ }
+ }
+ if(h2==0||l2==0){
+ if(!(p->q1.flags®)||p->q1.reg!=t1){
+ create_loadable(f,&p->q2,t1);
+ }else if(tmp=get_reg()){
+ create_loadable(f,&p->q2,tmp);
+ }
+ if(h2==0) h2=t2;
+ if(l2==0) l2=t2;
+ }
+ load_hword(f,h1,&p->q1,q1typ(p),0);
+ if(h2==-1){
+ emit(f,"\t%si\t%s,%s,",sh,mregnames[p->z.reg],mregnames[h1]);
+ if(p->typf&UNSIGNED)
+ emitzum(f,uhi);
+ else
+ emitzm(f,shi);
+ emit(f,"\n");
+ }else{
+ load_hword(f,h2,&p->q2,q2typ(p),t2);
+ emit(f,"\t%s\t%s,%s,%s\n",sh,mregnames[p->z.reg],mregnames[h1],mregnames[h2]);
+ }
+ if(c==BGT||c==BGE){
+ emit(f,"\tbgt\t%s,%s%d\n",mregnames[p->z.reg],labprefix,b->typf);
+ emit(f,"\tblt\t%s,%s%d\n",mregnames[p->z.reg],labprefix,falselab);
+ }else if(c==BLT||c==BLE){
+ emit(f,"\tblt\t%s,%s%d\n",mregnames[p->z.reg],labprefix,b->typf);
+ emit(f,"\tbgt\t%s,%s%d\n",mregnames[p->z.reg],labprefix,falselab);
+ }else if(c!=BNE){
+ emit(f,"\tbne\t%s,%s%d\n",mregnames[p->z.reg],labprefix,falselab);
+ }else{
+ emit(f,"\tbne\t%s,%s%d\n",mregnames[p->z.reg],labprefix,b->typf);
+ }
+
+ load_lword(f,l1,&p->q1,q1typ(p),t1);
+ if(l2==-1){
+ emit(f,"\tcmplwi\t%s,%s,",mregnames[p->z.reg],mregnames[l1]);
+ emitzm(f,lo);
+ emit(f,"\n");
+ }else{
+ load_lword(f,l2,&p->q2,q2typ(p),t2);
+ emit(f,"\tcmplw\t%s,%s,%s\n",mregnames[p->z.reg],mregnames[l1],mregnames[l2]);
+ }
+ emit(f,"\tb%s\t%s,%s%d\n",ccs[c-BEQ],mregnames[p->z.reg],labprefix,b->typf);
+ emit(f,"%s%d:\n",labprefix,falselab);
+ b->code=NOP;
+
+ return 1;
+ }
+
+ if(c==ADD||c==SUB||c==AND||c==OR||c==XOR){
+ /*FIXME: q2==z, q1reg+q2reg=zreg */
+ int zl,zh,l1,l2,h1,h2,tmp;
+ char *sl,*sh;
+ if(c==ADD){
+ sl="addc";
+ sh="adde";
+ }else if(c==SUB){
+ /* there is no subc, therefore we always use reverse order */
+ sl="subfc";
+ sh="subfe";
+ }else if(c==AND){
+ sl=sh="and";
+ }else if(c==OR){
+ sl=sh="or";
+ }else if(c==XOR){
+ sl=sh="xor";
+ }else
+ ierror(0);
+ l1=l2=h1=h2=zl=zh=0;
+ create_loadable(f,&p->q1,t1);
+ if(isreg(q1)){
+ if(!reg_pair(p->q1.reg,&rp)) ierror(0);
+ h1=rp.r1;
+ l1=rp.r2;
+ }else{
+ create_loadable(f,&p->q1,t1);
+ l1=t3;
+ h1=t1;
+ }
+ if(isreg(q2)){
+ if(!reg_pair(p->q2.reg,&rp)) ierror(0);
+ h2=rp.r1;
+ l2=rp.r2;
+ }else if(p->q2.flags&KONST){
+ /* check for immediates */
+ if(c==OR||c==XOR){
+ /* or and xor can always be done using (x)ori and (x)oris */
+ h2=l2=-1;
+ }
+ if(c==ADD){
+ zmax tmp;
+ eval_const(&p->q2.val,q2typ(p));
+ tmp=zmrshift(vmax,l2zm(32L));
+ /* there are addze and addme instructions */
+ if(zmeqto(tmp,l2zm(0L))||zmeqto(tmp,l2zm(-1L)))
+ h2=-1;
+ /* addic supports 16bit signed values */
+ tmp=zmrshift(zmlshift(vmax,l2zm(32L)),l2zm(32L));
+ if(zmleq(tmp,l2zm(32767L))&&zmleq(l2zm(-32768L),tmp))
+ l2=-1;
+ }
+ if(c==SUB){
+ zmax tmp;
+ eval_const(&p->q2.val,q2typ(p));
+ tmp=zmrshift(vmax,l2zm(32L));
+ /* there are addze and addme instructions */
+ if(zmeqto(tmp,l2zm(0L))||zmeqto(tmp,l2zm(1L)))
+ h2=-1;
+ /* addic supports 16bit signed values */
+ tmp=zmrshift(zmlshift(vmax,l2zm(32L)),l2zm(32L));
+ if(zmleq(tmp,l2zm(32768L))&&zmleq(l2zm(-32767L),tmp))
+ l2=-1;
+ }
+ }
+ if(!l2||!h2){
+ if(!(p->q1.flags®)||p->q1.reg!=t1){
+ create_loadable(f,&p->q2,t1);
+ }else if(tmp=get_reg()){
+ create_loadable(f,&p->q2,tmp);
+ }
+ if(h2==0) h2=t2;
+ if(l2==0) l2=t2;
+ }
+ if(isreg(z)&&(!isreg(q2)||p->z.reg!=p->q2.reg)){
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ zh=rp.r1;
+ zl=rp.r2;
+ }else{
+ zl=t3;
+ zh=t1;
+ }
+ if((p->q1.flags&KONST)&&l1==t3){
+ load_lword(f,t2,&p->q1,q1typ(p),0);
+ emit(f,"\tmr\t%s,%s\n",mregnames[t3],mregnames[t2]);
+ BSET(regs_modified,t3);
+ }else
+ load_lword(f,l1,&p->q1,q1typ(p),0);
+ if(l2!=-1){
+ load_lword(f,l2,&p->q2,q2typ(p),t2);
+ emit(f,"\t%s\t%s,%s,%s\n",sl,mregnames[zl],mregnames[l2],mregnames[l1]);
+ }else{
+ eval_const(&p->q2.val,q2typ(p));
+ if(c==ADD||c==SUB){
+ if(c==SUB) vmax=zmsub(l2zm(0L),vmax);
+ vmax=zmrshift(zmlshift(vmax,l2zm(32L)),l2zm(32L));
+ emit(f,"\taddic\t%s,%s,",mregnames[zl],mregnames[l1]);
+ emitzm(f,vmax);
+ emit(f,"\n");
+ }else if(c==OR||c==XOR){
+ zumax tmp;
+ if(zumeqto(zumand(vumax,ul2zum(0xffffffffUL)),ul2zum(0xffffffffUL))){
+ if(c==XOR)
+ emit(f,"\tnor\t%s,%s,%s\n",mregnames[zl],mregnames[l1],mregnames[l1]);
+ else
+ emit(f,"\tli\t%s,-1\n",mregnames[zl]);
+ }else{
+ tmp=zumand(vumax,ul2zum(0xffffUL));
+ if(!zumeqto(tmp,ul2zum(0UL))){
+ emit(f,"\t%si\t%s,%s,",sl,mregnames[zl],mregnames[l1]);
+ emitzum(f,tmp);
+ emit(f,"\n");
+ l1=zl;
+ }
+ tmp=zumand(zumrshift(vumax,ul2zum(16UL)),ul2zum(0xffff));
+ if(!zumeqto(tmp,ul2zum(0UL))){
+ emit(f,"\t%sis\t%s,%s,",sl,mregnames[zl],mregnames[l1]);
+ emitzum(f,tmp);
+ emit(f,"\n");
+ l1=zl;
+ }
+ if(l1!=zl)
+ emit(f,"\tmr\t%s,%s\n",mregnames[zl],mregnames[l1]);
+ }
+ }else
+ ierror(0);
+ }
+ if(h2!=-1){
+ load_hword(f,h2,&p->q2,q2typ(p),t2);
+ load_hword(f,h1,&p->q1,q1typ(p),0);
+ emit(f,"\t%s\t%s,%s,%s\n",sh,mregnames[zh],mregnames[h2],mregnames[h1]);
+ }else{
+ load_hword(f,h1,&p->q1,q1typ(p),0);
+ eval_const(&p->q2.val,q2typ(p));
+ if(c==ADD||c==SUB){
+ if(c==SUB) vmax=zmsub(l2zm(0L),vmax);
+ vmax=zmrshift(vmax,l2zm(32L));
+ if(zmeqto(vmax,l2zm(0L))){
+ emit(f,"\taddze\t%s,%s\n",mregnames[zh],mregnames[h1]);
+ }else if(zmeqto(vmax,l2zm(-1L))){
+ emit(f,"\taddme\t%s,%s\n",mregnames[zh],mregnames[h1]);
+ }else
+ ierror(0);
+ }else if(c==OR||c==XOR){
+ zumax tmp;
+ if(zumeqto(zumand(zumrshift(vumax,ul2zum(32L)),ul2zum(0xffffffffUL)),ul2zum(0xffffffffUL))){
+ if(c==XOR)
+ emit(f,"\tnor\t%s,%s,%s\n",mregnames[zh],mregnames[h1],mregnames[h1]);
+ else
+ emit(f,"\tli\t%s,-1\n",mregnames[zh]);
+ }else{
+ tmp=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffUL));
+ if(!zumeqto(tmp,ul2zum(0UL))){
+ emit(f,"\t%si\t%s,%s,",sl,mregnames[zh],mregnames[h1]);
+ emitzum(f,tmp);
+ emit(f,"\n");
+ h1=zh;
+ }
+ tmp=zumand(zumrshift(vumax,ul2zum(48UL)),ul2zum(0xffff));
+ if(!zumeqto(tmp,ul2zum(0UL))){
+ emit(f,"\t%sis\t%s,%s,",sl,mregnames[zh],mregnames[h1]);
+ emitzum(f,tmp);
+ emit(f,"\n");
+ h1=zh;
+ }
+ if(h1!=zh)
+ emit(f,"\tmr\t%s,%s\n",mregnames[zh],mregnames[h1]);
+ }
+ }
+ }
+ if(p->z.flags){
+ create_loadable(f,&p->z,t2);
+ store_lword(f,zl,&p->z);
+ store_hword(f,zh,&p->z);
+ p->z.flags=0;
+ }
+ return 1;
+ }
+
+ create_loadable(f,&p->q1,t1);
+
+ if(tmpoff>=32768&&(regs[r3]||regs[r4]||regs[r5]||regs[r6])){
+ emit(f,"\taddis\t%s,%s,%ld\n",mregnames[t2],mregnames[sp],hi(tmpoff));
+ if(lo(tmpoff)) emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t2],mregnames[t2],lo(tmpoff));
+ msp=t2;
+ mtmpoff=0;
+ }else{
+ msp=sp;
+ mtmpoff=tmpoff;
+ }
+
+ if(regs[r3]){ emit(f,"\tstw\t%s,%ld(%s)\n",mregnames[r3],mtmpoff-4,mregnames[msp]);savemask|=1;}
+ if(regs[r4]){ emit(f,"\tstw\t%s,%ld(%s)\n",mregnames[r4],mtmpoff-8,mregnames[msp]);savemask|=2;}
+ if(regs[r5]) {emit(f,"\tstw\t%s,%ld(%s)\n",mregnames[r5],mtmpoff-12,mregnames[msp]);savemask|=4;}
+ if(regs[r6]) {emit(f,"\tstw\t%s,%ld(%s)\n",mregnames[r6],mtmpoff-16,mregnames[msp]);savemask|=8;}
+
+ if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q1.reg>=r3&&p->q1.reg<=r6){
+ emit(f,"\tmr\t%s,%s\n",mregnames[t1],mregnames[p->q1.reg]);
+ p->q1.reg=t1;
+ }
+ if((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg>=r3&&p->q2.reg<=r6){
+ emit(f,"\tmr\t%s,%s\n",mregnames[t2],mregnames[p->q2.reg]);
+ p->q2.reg=t2;
+ }
+
+ if((q1typ(p)&NQ)==LLONG){
+ if(p->q1.am&&p->q1.am->base==r3){
+ if(p->q1.am->flags==REG_IND&&p->q1.am->offset==r4) ierror(0);
+ load_lword(f,r4,&p->q1,q1typ(p),0);
+ load_hword(f,r3,&p->q1,q1typ(p),0);
+ }else{
+ if(p->q1.am&&p->q1.am->flags==REG_IND&&p->q1.am->offset==r3) ierror(0);
+ load_hword(f,r3,&p->q1,q1typ(p),0);
+ load_lword(f,r4,&p->q1,q1typ(p),0);
+ }
+ }else{
+ if(!ISFLOAT(q1typ(p))) ierror(0);
+ load_reg(f,f1,&p->q1,q1typ(p),0);
+ }
+
+ if(p->q2.flags){
+ create_loadable(f,&p->q2,t2);
+ if((q2typ(p)&NQ)==LLONG){
+ if(isreg(q2)&&p->q2.reg==r3r4){
+ emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[r5],mtmpoff-4,mregnames[msp]);
+ emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[r6],mtmpoff-8,mregnames[msp]);
+ }else{
+ if(p->q2.am&&p->q2.am->base==r5){
+ if(p->q2.am->flags==REG_IND&&p->q2.am->offset==r6) ierror(0);
+ load_lword(f,r6,&p->q2,q2typ(p),0);
+ load_hword(f,r5,&p->q2,q2typ(p),0);
+ }else{
+ if(p->q2.am&&p->q2.am->flags==REG_IND&&p->q2.am->offset==r5) ierror(0);
+ load_hword(f,r5,&p->q2,q2typ(p),0);
+ load_lword(f,r6,&p->q2,q2typ(p),0);
+ }
+ }
+ }else{
+ if((q2typ(p)&NQ)>=LLONG) ierror(0);
+ if(isreg(q2)&&p->q2.reg==r3){
+ emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[r5],mtmpoff-4,mregnames[msp]);
+ }else{
+ load_reg(f,r5,&p->q2,q2typ(p),0);
+ }
+ }
+ }
+
+ if(c==MULT) libfuncname="__mulint64";
+ else if(c==DIV){
+ if(t&UNSIGNED)
+ libfuncname="__divuint64";
+ else
+ libfuncname="__divsint64";
+ }else if(c==MOD){
+ if(t&UNSIGNED)
+ libfuncname="__moduint64";
+ else
+ libfuncname="__modsint64";
+ }else if(c==CONVERT){
+ static char s[32];
+ if(ISFLOAT(q1typ(p)))
+ sprintf(s,"__flt%dto%cint64",(q1typ(p)&NQ)==FLOAT?32:64,(ztyp(p)&UNSIGNED)?'u':'s');
+ else
+ sprintf(s,"__%cint64toflt%d",(q1typ(p)&UNSIGNED)?'u':'s',(ztyp(p)&NQ)==FLOAT?32:64);
+ libfuncname=s;
+ }else if(c==RSHIFT){
+ if(t&UNSIGNED)
+ libfuncname="__rshuint64";
+ else
+ libfuncname="__rshsint64";
+ }else if(c==LSHIFT)
+ libfuncname="__lshint64";
+ else{
+ printf("c=%d\n",c);
+ ierror(0);
+ }
+ emit(f,"\t.global\t%s%s\n",idprefix,libfuncname);
+ emit(f,"\tbl\t%s%s\n",idprefix,libfuncname);
+ stack_valid=0; /*FIXME*/
+
+ if((p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ if((p->z.reg==r3&&(savemask&1))||
+ (p->z.reg==r4&&(savemask&2))||
+ (p->z.reg==r5&&(savemask&4))||
+ (p->z.reg==r6&&(savemask&8))){
+ if(p->z.reg==r3)
+ emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[t1],mtmpoff-4,mregnames[msp]);
+ else if(p->z.reg==r4)
+ emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[t1],mtmpoff-8,mregnames[msp]);
+ else if(p->z.reg==r5)
+ emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[t1],mtmpoff-12,mregnames[msp]);
+ else if(p->z.reg==r6)
+ emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[t1],mtmpoff-16,mregnames[msp]);
+ else
+ ierror(0);
+ p->z.reg=t1;
+ }
+ }
+
+ if((p->z.flags®)&&p->z.reg==r3)
+ savemask&=~1;
+ if((p->z.flags®)&&p->z.reg==r4)
+ savemask&=~2;
+ if((p->z.flags®)&&p->z.reg==r5)
+ savemask&=~4;
+ if((p->z.flags®)&&p->z.reg==r6)
+ savemask&=~8;
+ if((p->z.flags®)&&p->z.reg==r3r4)
+ savemask&=~3;
+ if((p->z.flags®)&&p->z.reg==r5r6)
+ savemask&=~12;
+
+
+ if(ISFLOAT(ztyp(p))){
+ zreg=f1;
+ }else{
+ create_loadable(f,&p->z,t1);
+ store_hword(f,r3,&p->z);
+ store_lword(f,r4,&p->z);
+ p->z.flags=0;
+ }
+
+ if(savemask&1)
+ emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[r3],mtmpoff-4,mregnames[msp]);
+ if(savemask&2)
+ emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[r4],mtmpoff-8,mregnames[msp]);
+ if(savemask&4)
+ emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[r5],mtmpoff-12,mregnames[msp]);
+ if(savemask&8)
+ emit(f,"\tlwz\t%s,%ld(%s)\n",mregnames[r6],mtmpoff-16,mregnames[msp]);
+
+ return 1;
+}
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+
+int init_cg(void)
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(8L);
+ if(POWEROPEN){
+ stackalign=l2zm(4L);
+ align_arguments=0;
+ }else{
+ tocname=sdataname;
+ stackalign=l2zm(4L);
+ if(NOALIGNARGS)
+ align_arguments=0;
+ else
+ align_arguments=1;
+ }
+ char_bit=l2zm(8L);
+ if(g_flags[7]&USEDFLAG){
+ malign[INT]=malign[LONG]=malign[LLONG]=malign[POINTER]=malign[FLOAT]=malign[DOUBLE]=malign[LDOUBLE]=2;
+ }
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+ for(i=0;i<=MAXR;i++) mregnames[i]=regnames[i];
+ for(i= 1;i<=32;i++){
+ regsize[i]=l2zm(4L);
+ regtype[i]=<yp;
+ if(g_flags[8]&USEDFLAG) mregnames[i]++;
+ }
+ for(i=33;i<=64;i++){
+ regsize[i]=l2zm(8L);
+ regtype[i]=&ldbl;
+ if(g_flags[8]&USEDFLAG) mregnames[i]++;
+ }
+ for(i=65;i<=72;i++){
+ regsize[i]=l2zm(1L);
+ regtype[i]=&lchar;
+ if(g_flags[8]&USEDFLAG) mregnames[i]+=2;
+ }
+ for(i=74;i<=86;i++){
+ regsize[i]=l2zm(8L);
+ regtype[i]=&lltyp;
+ }
+
+ /* Use multiple ccs. */
+ multiple_ccs=1;
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LONG]=t_min(INT);
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=ul2zum(2147483647UL);
+ t_max[LONG]=t_max(INT);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=ul2zum(4294967295UL);
+ tu_max[LONG]=t_max(UNSIGNED|INT);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ /* This is not optimal but simple. */
+ if(POWEROPEN){
+ sd=r2;
+ }
+ regsa[t1]=regsa[t2]=regsa[t3]=1;
+ regsa[f1]=regsa[f2]=regsa[f3]=1;
+ regsa[sp]=regsa[fp]=regsa[sd]=regsa[r2]=1;
+ regscratch[t1]=regscratch[t2]=regscratch[t3]=0;
+ regscratch[f1]=regscratch[f2]=regscratch[f3]=0;
+ regscratch[sp]=regscratch[fp]=regscratch[sd]=regscratch[r2]=0;
+
+ if(g_flags[6]&USEDFLAG) {minframe=8;labprefix=".l";idprefix="";}
+ if(POWEROPEN) {minframe=24;labprefix="l";idprefix="_";}
+
+ if(optsize){
+ dataname="\t.data\n";
+ rodataname="\t.section\t.rodata\n";
+ sdataname="\t.section\t\".sdata\",\"aw\"\n";
+ sdata2name="\t.section\t\".sdata2\",\"a\"\n";
+ sbssname="\t.section\t\".sbss\",\"auw\"\n";
+ }
+
+ if(BASERELOS4) bssname="\t.bss\n";
+
+ target_macros=marray;
+
+ declare_builtin("__mulint64",LLONG,LLONG,r3r4,LLONG,r5r6,1,0);
+ declare_builtin("__divsint64",LLONG,LLONG,r3r4,LLONG,r5r6,1,0);
+ declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,r3r4,UNSIGNED|LLONG,r5r6,1,0);
+ declare_builtin("__modsint64",LLONG,LLONG,r3r4,LLONG,r5r6,1,0);
+ declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,r3r4,UNSIGNED|LLONG,r5r6,1,0);
+ declare_builtin("__lshint64",LLONG,LLONG,r3r4,INT,r5,1,0);
+ declare_builtin("__rshsint64",LLONG,LLONG,r3r4,INT,r5,1,0);
+ declare_builtin("__rshuint64",LLONG,UNSIGNED|LLONG,r3r4,INT,r5,1,0);
+
+ return 1;
+}
+
+void init_db(FILE *f)
+{
+ dwarf2_setup(sizetab[POINTER],".byte",".2byte",".4byte",".4byte",labprefix,idprefix,".section");
+ dwarf2_print_comp_unit_header(f);
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+/* A pointer MUST be returned in a register. The code-generator */
+/* has to simulate a pseudo register if necessary. */
+{
+ if(ISFLOAT(t->flags)) return 34; /* f1 */
+ if(ISSTRUCT(t->flags)||ISUNION(t->flags)) return 0;
+ if(zmleq(szof(t),l2zm(4L))) return r3;
+ if((t->flags&NQ)==LLONG) return 74; /* r3/r4 */
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ if(r<74||r>86)
+ return 0;
+ switch(r){
+ case 74: p->r1=4;p->r2=5;return 1;
+ case 75: p->r1=6;p->r2=7;return 1;
+ case 76: p->r1=8;p->r2=9;return 1;
+ case 77: p->r1=10;p->r2=11;return 1;
+ case 78: p->r1=15;p->r2=16;return 1;
+ case 79: p->r1=17;p->r2=18;return 1;
+ case 80: p->r1=19;p->r2=20;return 1;
+ case 81: p->r1=21;p->r2=22;return 1;
+ case 82: p->r1=23;p->r2=24;return 1;
+ case 83: p->r1=25;p->r2=26;return 1;
+ case 84: p->r1=27;p->r2=28;return 1;
+ case 85: p->r1=29;p->r2=30;return 1;
+ case 86: p->r1=31;p->r2=32;return 1;
+ }
+ ierror(0);
+}
+
+
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+ int c=p->code;
+ if(o->flags&VKONST){
+ struct obj *co=&o->v->cobj;
+ int longload;
+ if(o->flags&DREFOBJ)
+ return 4;
+ if(ISFLOAT(p->typf)) return 2;
+ longload=0;
+ if((co->flags&VARADR)&&!use_sd(o->v->vtyp->flags))
+ longload=2;
+ if(co->flags&KONST){
+ eval_const(&co->val,p->typf);
+ if(p->typf&UNSIGNED){
+ if(!zumleq(vumax,ul2zum(65535UL)))
+ longload=2;
+ }else{
+ if(!zmleq(vmax,l2zm(32767L))||zmleq(vmax,l2zm(-32769L)))
+ longload=2;
+ }
+ }
+ if(o==&p->q1&&p->code==ASSIGN&&((p->z.flags&DREFOBJ)||p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN))
+ return longload+2;
+ else
+ return longload;
+ }
+ if(o->flags&DREFOBJ)
+ return 4;
+ if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+ if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+ return 2;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(r==0) return 0;
+ t&=NQ;
+ if(t==0){
+ if(r>=65&&r<=72) return 1; else return 0;
+ }
+ if(ISFLOAT(t)&&r>=33&&r<=64) return 1;
+ if(t==POINTER&&r>=1&&r<=32) return 1;
+ if(t>=CHAR&&t<=LONG&&r>=1&&r<=32) return 1;
+ if(t==LLONG&&r>=74&&r<=86) return 1;
+ return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!(p->q2.flags&KONST))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* On the PowerPC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op=o&NQ,tp=t&NQ;
+ if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
+ return 0;
+ if(op==DOUBLE&&tp==LDOUBLE) return 0;
+ if(op==LDOUBLE&&tp==DOUBLE) return 0;
+ if(op==tp) return 0;
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ title(f);
+ if(newobj&§ion!=TOC&§ion!=SBSS&§ion!=SPECIAL&&!BASERELOS4)
+ emit(f,"%ld\n",zm2l(size));
+ else
+ emit(f,"\t.space\t%ld\n",zm2l(size));
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ title(f);
+ if(!optsize&&(zm2l(align)<4))
+ emit(f,"\t.align\t2\n");
+ else
+ if(zm2l(align)>1)
+ emit(f,"\t.align\t%ld\n",pof2(align)-1);
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;char *sec;
+ title(f);
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(!special_section(f,v)){
+ if(use_sd(v->vtyp->flags)&&!(v->tattr&FAR)){
+ if(EABI){
+ if(v->clist&&!constflag&§ion!=SDATA){emit(f,sdataname);if(f) section=SDATA;}
+ if(v->clist&&constflag&§ion!=SDATA2){emit(f,sdata2name);if(f) section=SDATA2;}
+ if(!v->clist&§ion!=SBSS){emit(f,sbssname);if(f) section=SBSS;}
+ }else if (POWEROPEN){
+ if(section!=TOC){emit(f,tocname);if(f) section=TOC;}
+ }
+ else {
+ if(v->clist&§ion!=SDATA){emit(f,sdataname);if(f) section=SDATA;}
+ if(!v->clist&§ion!=SBSS){emit(f,sbssname);if(f) section=SBSS;}
+ }
+ }else{
+ if(BASERELOS4){
+ if(v->clist&§ion!=DATA){emit(f,dataname); if(f) section=DATA;}
+ }else if(BASERELMOS){
+ if(v->clist&§ion!=SDATA){emit(f,sdataname); if(f) section=SDATA;}
+ if(!v->clist&§ion!=SBSS){emit(f,sbssname); if(f) section=SBSS;}
+ }else{
+ if(POWEROPEN) toc_entry(f,v);
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!USE_COMMONS&&!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ }
+ }
+ if(v->clist||section==TOC||section==SBSS||section==SPECIAL){
+ emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset));
+ emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp)));
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }else{
+ emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+ newobj=1;
+ }
+ }
+ if(v->storage_class==EXTERN){
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ if(POWEROPEN&&(!use_sd(v->vtyp->flags)||(v->tattr&FAR)))
+ emit(f,"\t.global\t%s%s%s\n",tocprefix,idprefix,v->identifier);
+ if(v->flags&(DEFINED|TENTATIVE)){
+ if(!special_section(f,v)){
+ if(use_sd(v->vtyp->flags)&&!(v->tattr&FAR)){
+ if(EABI){
+ if(v->clist&&!constflag&§ion!=SDATA){emit(f,sdataname);if(f) section=SDATA;}
+ if(v->clist&&constflag&§ion!=SDATA2){emit(f,sdata2name);if(f) section=SDATA2;}
+ if(!v->clist&§ion!=SBSS){emit(f,sbssname);if(f) section=SBSS;}
+ }else if (POWEROPEN){
+ if(section!=TOC){emit(f,tocname);if(f) section=TOC;}
+ }
+ else {
+ if(v->clist&§ion!=SDATA){emit(f,sdataname);if(f) section=SDATA;}
+ if(!USE_COMMONS&&!v->clist&§ion!=SBSS){emit(f,sbssname);if(f) section=SBSS;}
+ }
+ }else{
+ if(BASERELOS4){
+ if(v->clist&§ion!=DATA){emit(f,dataname); if(f) section=DATA;}
+ }else if(BASERELMOS){
+ if(v->clist&§ion!=SDATA){emit(f,sdataname); if(f) section=SDATA;}
+ if(!USE_COMMONS&&!v->clist&§ion!=SBSS){emit(f,sbssname); if(f) section=SBSS;}
+ }else{
+ if(POWEROPEN) toc_entry(f,v);
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!USE_COMMONS&&!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ }
+ }
+ if(v->clist||section==TOC||section==SBSS||section==SPECIAL){
+ emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
+ emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp)));
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else{
+ emit(f,"\t.%scomm\t%s%s,",USE_COMMONS?"":"l",idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ title(f);
+ if((t&NQ)==POINTER) t=UNSIGNED|LONG;
+ emit(f,"\t.%s\t",dct[t&NQ]);
+ if(!p->tree){
+ if(ISFLOAT(t)){
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ if((t&NQ)!=FLOAT){
+ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ }else if((t&NQ)==LLONG){
+ zumax tmp;
+ eval_const(&p->val,t);
+ tmp=vumax;
+ vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff));
+ gval.vulong=zum2zul(vumax);
+ emitval(f,&gval,UNSIGNED|LONG);
+ emit(f,",");
+ vumax=zumand(tmp,ul2zum(0xffffffff));
+ gval.vulong=zum2zul(vumax);
+ emitval(f,&gval,UNSIGNED|LONG);
+ }else{
+ emitval(f,&p->val,t&NU);
+ }
+ }else{
+ emit_obj(f,&p->tree->o,t&NU);
+ }
+ emit(f,"\n");newobj=0;
+}
+
+static void allocreg(int r)
+{
+ if(reg_pair(r,&rp)){
+ regs[rp.r1]=1;
+ regs[rp.r2]=1;
+ }
+ regs[r]=1;
+}
+
+static void freereg(int r)
+{
+ if(reg_pair(r,&rp)){
+ regs[rp.r1]=0;
+ regs[rp.r2]=0;
+ }
+ regs[r]=0;
+}
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/* The main code-generation. */
+{
+ int c,t,i,addbuf,varargs=0,fixedgpr,fixedfpr,setcc,ccset;
+ char *fpp;int fpf;struct IC *m;
+ long of=(zm2l(offset)+3)/4*4,regbase,vparmos=0;
+ if(DEBUG&1) printf("gen_code()\n");
+ for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+ if(vlas) fp=vlafp; else fp=sp;
+ maxpushed=0;addbuf=0;
+ if(v->tattr&RFI)
+ ret="\trfi\n";
+ else
+ ret="\tblr\n";
+ if(!v->fi) v->fi=new_fi();
+ title(f);
+ for(m=p;m;m=m->next){
+ c=m->code;t=m->typf&NU;
+ m->ext.setcc=0;
+ if(c==ALLOCREG){
+ allocreg(m->q1.reg);
+ continue;
+ }
+ if(c==FREEREG){
+ freereg(m->q1.reg);
+ continue;
+ }
+ if(c==COMPARE&&(m->q2.flags&KONST)&&(t&NQ)!=CHAR&&(t&NQ)!=SHORT){
+ eval_const(&m->q2.val,t);
+ if(zmeqto(vmax,l2zm(0L))&&zldeqto(vldouble,d2zld(0.0))){
+ m->q2.flags=0;m->code=c=TEST;
+ }
+ }
+ if((t&NQ)<=LLONG&&(m->q2.flags&KONST)&&(t&NQ)<=LLONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+ eval_const(&m->q2.val,t);
+ i=pof2(vmax);
+ if(i){
+ if(c==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ m->code=AND;
+ }else{
+ vmax=l2zm(i-1);
+ if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+ }
+ c=m->code;
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ if(c==AND){
+ insert_const(&m->q2.val,t);
+ }else{
+ insert_const(&m->q2.val,INT);
+ m->typf2=INT;
+ }
+ }
+ }
+ if(addbuf<16){
+ if((q1typ(m)&NQ)==LLONG&&(c==MULT||c==DIV||c==MOD||c==LSHIFT||c==RSHIFT)) {addbuf=16;function_calls++;}
+ if(c==CONVERT&&(q1typ(m)&NQ)==LLONG&&ISFLOAT(ztyp(m)&NQ)){addbuf=16;function_calls++;}
+ if(c==CONVERT&&(ztyp(m)&NQ)==LLONG&&ISFLOAT(q1typ(m)&NQ)){addbuf=16;function_calls++;}
+ if(addbuf<8){
+ if(c==CONVERT&&ISFLOAT(m->typf2)&&!ISFLOAT(t)) addbuf=8;
+ if(c==CONVERT&&!ISFLOAT(m->typf2)&&ISFLOAT(t)) addbuf=8;
+ }
+ }
+ if(c==CALL&&maxpushed<zm2l(m->q2.val.vmax)) maxpushed=zm2l(m->q2.val.vmax);
+ if(c==CALL&&(m->q1.flags&VAR)&&!strcmp(m->q1.v->identifier,"__va_start")) varargs=1;
+ }
+ once=twice=0;
+ if(!(g_flags[9]&USEDFLAG)) peephole(p);
+ if(varargs){
+ fixedgpr=fixedfpr=0;
+ if(!freturn(v->vtyp->next)) fixedgpr++;
+ for(i=0;i<v->vtyp->exact->count;i++){
+ c=(*v->vtyp->exact->sl)[i].styp->flags&NQ;
+ if(fixedgpr<8&&(c==POINTER||c<=LONG))
+ fixedgpr++;
+ else if(fixedgpr<7&&c==LLONG)
+ fixedgpr=(fixedgpr+3)/2*2;
+ else if(fixedfpr<8&&ISFLOAT(c))
+ fixedfpr++;
+ else{
+
+ vparmos+=zm2l(szof((*v->vtyp->exact->sl)[i].styp));
+ vparmos=(vparmos+zm2l(stackalign)-1)/zm2l(stackalign)*zm2l(stackalign);
+ }
+ }
+ regbase=of;
+ addbuf+=96;
+ }
+ for(c=1;c<=MAXR;c++){
+ if((!regsa[c])&®used[c]){
+ BSET(regs_modified,c);
+ }
+ }
+ of+=addbuf;tmpoff=minframe+maxpushed+of;
+ function_top(f,v,of);
+ all_regs=1;
+ if(varargs){
+ regbase=frameoffset+regbase;
+ fpp="";
+ if(!(g_flags[8]&USEDFLAG)) fpp="r";
+ for(i=fixedgpr;i<8;i++)
+ emit(f,"\tstw\t%s%d,%ld(%s)\n",fpp,i+3,regbase+i*4,mregnames[sp]);
+ if(!(g_flags[8]&USEDFLAG)) fpp="f";
+ for(i=fixedfpr;i<8;i++)
+ emit(f,"\tstfd\t%s%d,%ld(%s)\n",fpp,i+1,regbase+32+i*8,mregnames[sp]);
+ }
+ pushed=0;ccset=0;
+ for(;p;pr(f,p),p=p->next){
+ c=p->code;t=p->typf;
+ setcc=p->ext.setcc;
+ if(debug_info)
+ dwarf2_line_info(f,p);
+ if(c==NOP) {p->z.flags=0;continue;}
+ if(c==ALLOCREG){
+ allocreg(p->q1.reg);
+ continue;
+ }
+ if(c==FREEREG){
+ freereg(p->q1.reg);
+ continue;
+ }
+ if(c==COMPARE&&(p->q2.flags&KONST)&&(t&NQ)!=LLONG){
+ struct case_table *ct=calc_case_table(p,JUMP_TABLE_DENSITY);
+ if(ct&&(ct->num>=JUMP_TABLE_LENGTH||(!isreg(q1)&&ct->num>=JUMP_TABLE_LENGTH/2))){
+ int r,defl,tabl=++label;
+ long l;unsigned long ul;
+ struct IC *np;
+ for(np=p;np!=ct->next_ic;np=np->next){
+ if(np->code==ALLOCREG) allocreg(np->q1.reg);
+ if(np->code==FREEREG) freereg(np->q1.reg);
+ }
+ if(ct->next_ic->code==BRA)
+ defl=ct->next_ic->typf;
+ else
+ defl=++label;
+ if(!isreg(q1)){
+ if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==DREFOBJ){
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,t1,&p->q1,POINTER,t1);
+ p->q1.flags|=(REG|DREFOBJ);
+ p->q1.flags&=~VAR;
+ p->q1.reg=t1;
+ }
+ load_reg(f,t2,&p->q1,p->typf,t1);
+ r=t2;
+ }else
+ r=p->q1.reg;
+ if(t&UNSIGNED)
+ l=-(long)zum2ul(ct->min.vumax);
+ else
+ l=-zm2l(ct->min.vmax);
+ if(l>=-32767&&l<=32767){
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t2],mregnames[r],l);
+ }else{
+ emit(f,"\taddis\t%s,%s,%ld\n",mregnames[t2],mregnames[r],hi(l));
+ if(lo(l))
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t2],mregnames[t2],lo(l));
+ }
+ ul=zum2ul(ct->diff);
+ if(regs[cr0]) ierror(0);
+ if(ul<=65535){
+ emit(f,"\tcmplwi\t%s,%lu\n",mregnames[t2],ul);
+ }else{
+ emit(f,"\tlis\t%s,%ld\n",mregnames[t1],hi(ul));
+ if(lo(ul))
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t1],regnames[t1],lo(ul));
+ }
+ emit(f,"\tbgt\t%s,%s%d\n",mregnames[cr0],labprefix,defl);
+ emit(f,"\tslwi\t%s,%s,2\n",mregnames[t2],mregnames[t2]);
+ /*FIXME: small-data */
+ if(POWEROPEN){
+ emit(f,"\tlwz\t%s,%s%s%d(%s)\n",mregnames[t1],tocprefix,labprefix,tabl,mregnames[r2]);
+ }else{
+ emit(f,"\tlis\t%s,%s%d@ha\n",mregnames[t1],labprefix,tabl);
+ emit(f,"\taddi\t%s,%s,%s%d@l\n",mregnames[t1],mregnames[t1],labprefix,tabl);
+ }
+ emit(f,"\tlwzx\t%s,%s,%s\n",mregnames[t2],mregnames[t1],mregnames[t2]);
+ emit(f,"\tmtctr\t%s\n",mregnames[t2]);
+ emit(f,"\tbctr\n");
+ BSET(regs_modified,ctr);
+ if(POWEROPEN){
+ emit(f,tocname);
+ emit(f,"%s%s%d:\n",tocprefix,labprefix,tabl);
+ emit(f,"\t.long\t%s%d\n",labprefix,tabl);
+ }
+ emit(f,rodataname);
+ emit(f,"\t.align\t2\n");
+ emit(f,"%s%d:\n",labprefix,tabl);
+ emit_jump_table(f,ct,"\t.long\t",labprefix,defl);
+ if(!special_section(f,v)) emit(f,codename);
+ if(ct->next_ic->code!=BRA){
+ emit(f,"%s%d:\n",labprefix,defl);
+ p=ct->next_ic->prev;
+ }else
+ p=ct->next_ic;
+ continue;
+ }
+ }
+ if(c==LABEL) {ccset=0;emit(f,"%s%d:\n",labprefix,t);continue;}
+ if(c==BRA){
+ ccset=0;
+ if(t==exit_label&&framesize==0)
+ emit(f,ret);
+ else
+ emit(f,"\tb\t%s%d\n",labprefix,t);
+ continue;
+ }
+ if(c>=BEQ&&c<BRA){
+ ccset=0;
+ if(!(p->q1.flags®)) p->q1.reg=cr0;
+ if(!(g_flags[9]&USEDFLAG)&&!BTST(twice,p->typf-lastlabel)){
+ struct IC *p2,*p3,*p4;int exit_label;
+ p2=p->next;
+ while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
+ if(p2&&p2->code==SETRETURN&&p2->z.reg){p2->code=ASSIGN;p2->z.flags=REG;}
+ if(p2&&p2->code==ASSIGN&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg<=32){
+ p3=p2->next;
+ while(p3&&(p3->code==FREEREG||p3->code==ALLOCREG)) p3=p3->next;
+ if(p3&&p3->code==BRA){
+ exit_label=p3->typf;
+ p3=p3->next;
+ while(p3&&(p3->code==FREEREG||p3->code==ALLOCREG)) p3=p3->next;
+ if(p3&&p3->code==LABEL&&p3->typf==p->typf){
+ p3=p3->next;
+ while(p3&&(p3->code==FREEREG||p3->code==ALLOCREG)) p3=p3->next;
+ if(p3&&p3->code==SETRETURN&&p3->z.reg){p3->code=ASSIGN;p3->z.flags=REG;}
+ if(p3&&p3->code==ASSIGN&&(p3->z.flags&(REG|DREFOBJ))==REG&&p3->z.reg==p2->z.reg){
+ p4=p3->next;
+ while(p4&&(p4->code==FREEREG||p4->code==ALLOCREG)) p4=p4->next;
+ if(p4&&p4->code==LABEL&&p4->typf==exit_label){
+ int bit=(p->q1.reg-cr0)*4;
+ if((p2->q1.flags&KONST)&&(p3->q1.flags&KONST)){
+ eval_const(&p2->q1.val,p2->typf);
+ if(zmeqto(vmax,l2zm(0L))){
+ eval_const(&p3->q1.val,p3->typf);
+ if(zmeqto(vmax,l2zm(1L))||zmeqto(vmax,l2zm(-1L))){
+ if(c==BLE){emit(f,"\tcror\t%d,%d,%d\n",bit,bit,bit+2);}
+ if(c==BGE){bit++;emit(f,"\tcror\t%d,%d,%d\n",bit,bit,bit+1);}
+ if(c==BNE){bit+=2;emit(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit);}
+ if(c==BGT) bit++;
+ if(c==BEQ) bit+=2;
+ emit(f,"\tmfcr\t%s\n",mregnames[t1]);
+ emit(f,"\trlwinm\t%s,%s,%d,%d,%d\n",mregnames[p2->z.reg],mregnames[t1],bit+1,31,31);
+ if(zmeqto(vmax,l2zm(-1L))) emit(f,"\tneg\t%s,%s\n",mregnames[p2->z.reg],mregnames[p2->z.reg]);
+ if(BTST(twice,p4->typf-lastlabel)) emit(f,"%s%d:\n",labprefix,p4->typf);
+ p=p4;continue;
+ }
+ }else{
+ eval_const(&p3->q1.val,p3->typf);
+ if(zmeqto(vmax,l2zm(0L))){
+ eval_const(&p2->q1.val,p2->typf);
+ if(zmeqto(vmax,l2zm(1L))||zmeqto(vmax,l2zm(-1L))){
+ if(c==BLE){emit(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit+2);}
+ if(c==BGE){bit++;emit(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit+1);}
+ if(c==BNE){bit+=2;}
+ if(c==BGT){bit++;emit(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit);}
+ if(c==BEQ){bit+=2;emit(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit);}
+ if(c==BLT){emit(f,"\tcrnor\t%d,%d,%d\n",bit,bit,bit);}
+ emit(f,"\tmfcr\t%s\n",mregnames[t1]);
+ emit(f,"\trlwinm\t%s,%s,%d,%d,%d\n",mregnames[p2->z.reg],mregnames[t1],bit+1,31,31);
+ if(zmeqto(vmax,l2zm(-1L))) emit(f,"\tneg\t%s,%s\n",mregnames[p2->z.reg],mregnames[p2->z.reg]);
+ if(BTST(twice,p4->typf-lastlabel)) emit(f,"%s%d:\n",labprefix,p4->typf);
+ p=p4;continue;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if(t==exit_label&&framesize==0&&!strcmp(ret,"\tblr\n"))
+ emit(f,"\tb%slr\t%s\n",ccs[c-BEQ],mregnames[p->q1.reg]);
+ else
+ emit(f,"\tb%s\t%s,%s%d\n",ccs[c-BEQ],mregnames[p->q1.reg],labprefix,t);
+ continue;
+ }
+ if(c==MOVETOREG){
+ if(p->z.reg<=32){
+ load_reg(f,p->z.reg,&p->q1,INT,t1);
+ }else if(p->z.reg>=33&&p->z.reg<=64){
+ load_reg(f,p->z.reg,&p->q1,DOUBLE,t1);
+ }else if(reg_pair(p->z.reg,&rp)){
+ create_loadable(f,&p->q1,t1);
+ load_hword(f,rp.r1,&p->q1,LLONG,t2);
+ load_lword(f,rp.r2,&p->q1,LLONG,t2);
+ }else
+ ierror(0);
+ p->z.flags=0;
+ continue;
+ }
+ if(c==MOVEFROMREG){
+ if(p->q1.reg<=32){
+ store_reg(f,p->q1.reg,&p->z,INT);
+ }else if(p->q1.reg>=33&&p->q1.reg<=64){
+ store_reg(f,p->q1.reg,&p->z,DOUBLE);
+ }else if(reg_pair(p->q1.reg,&rp)){
+ create_loadable(f,&p->z,t1);
+ store_hword(f,rp.r1,&p->z);
+ store_lword(f,rp.r2,&p->z);
+ }else
+ ierror(0);
+ p->z.flags=0;
+ continue;
+ }
+ if((p->q1.flags&&(q1typ(p)&NQ)==LLONG)||(p->q2.flags&&(q2typ(p)&NQ)==LLONG)||(p->z.flags&&(ztyp(p)&NQ)==LLONG))
+ if(handle_llong(f,p))
+ continue;
+ if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+ unsigned long size,l;
+ int a1,a2,b;char *ld,*st;
+ size=zm2l(p->q2.val.vmax);
+ a1=balign(&p->q1);
+ if(c==ASSIGN) a2=balign(&p->z); else a2=0;
+ b=1;ld=ldt(CHAR);st=sdt(CHAR);
+ if(p->q1.flags&VAR){
+ if(p->q1.flags&DREFOBJ){
+ if(p->q1.v->vtyp->next&&zmeqto(p->q2.val.vmax,szof(p->q1.v->vtyp->next))&&(a1&1)){
+ a1=zm2l(falign(p->q1.v->vtyp->next))&3;
+ a2&=a1;
+ }
+ }else{
+ if(zmeqto(p->q2.val.vmax,szof(p->q1.v->vtyp))&&(a1&1)){
+ a1=zm2l(falign(p->q1.v->vtyp))&3;
+ a2&=a1;
+ }
+ }
+ }
+ if(p->z.flags&VAR){
+ if(p->z.flags&DREFOBJ){
+ if(p->z.v->vtyp->next&&zmeqto(p->q2.val.vmax,szof(p->z.v->vtyp->next))&&(a2&1)){
+ a2=zm2l(falign(p->z.v->vtyp->next))&3;
+ a1&=a2;
+ }
+ }else{
+ if(zmeqto(p->q2.val.vmax,szof(p->z.v->vtyp))&&(a2&1)){
+ a2=zm2l(falign(p->z.v->vtyp))&3;
+ a1&=a2;
+ }
+ }
+ }
+ if(a1>=0&&a2>=0){
+ if(a1==0&&a2==0){
+ b=4;ld=ldt(INT);st=sdt(INT);
+ }else if((a1&1)==0&&(a2&1)==0){
+ b=2;ld=ldt(SHORT);st=sdt(SHORT);
+ }
+ }
+ if(p->q1.flags&DREFOBJ){
+ if(p->q1.am){
+ if(p->q1.am->flags®_IND){
+ emit(f,"\tadd\t%s,%s,%s\n",mregnames[t1],mregnames[p->q1.am->offset],mregnames[p->q1.am->base]);
+ emit(f,"\taddi\t%s,%s,%d\n",mregnames[t1],mregnames[t1],-b);
+ }
+ if(p->q1.am->flags&IMM_IND)
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t1],mregnames[p->q1.am->base],p->q1.am->offset-b);
+ }else{
+ p->q1.flags&=~DREFOBJ;
+ if(isreg(q1)){
+ emit(f,"\taddi\t%s,%s,%d\n",mregnames[t1],mregnames[p->q1.reg],-b);
+ }else{
+ load_reg(f,t1,&p->q1,POINTER,t1);
+ emit(f,"\taddi\t%s,%s,%d\n",mregnames[t1],mregnames[t1],-b);
+ }
+ p->q1.flags|=DREFOBJ;
+ }
+ }else{
+ p->q1.val.vmax=zmsub(p->q1.val.vmax,l2zm((long)b));
+ load_address(f,t1,&p->q1,POINTER);
+ p->q1.val.vmax=zmadd(p->q1.val.vmax,l2zm((long)b));
+ }
+ if(p->z.flags&DREFOBJ){
+ if(p->z.am){
+ if(p->z.am->flags®_IND){
+ emit(f,"\tadd\t%s,%s,%s\n",mregnames[t2],mregnames[p->z.am->offset],mregnames[p->z.am->base]);
+ emit(f,"\taddi\t%s,%s,%d\n",mregnames[t2],mregnames[t2],-b);
+ }
+ if(p->z.am->flags&IMM_IND)
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t2],mregnames[p->z.am->base],p->z.am->offset-b);
+ }else{
+ p->z.flags&=~DREFOBJ;
+ if(isreg(z)){
+ emit(f,"\taddi\t%s,%s,%d\n",mregnames[t2],mregnames[p->z.reg],-b);
+ }else{
+ load_reg(f,t2,&p->z,POINTER,t2);
+ emit(f,"\taddi\t%s,%s,%d\n",mregnames[t2],mregnames[t2],-b);
+ }
+ p->z.flags|=DREFOBJ;
+ }
+ }else{
+ if(c==PUSH){
+ pushed=(pushed+3)/4*4;
+ if(align_arguments&&p->ityp){
+ long al=falign(p->ityp);
+ pushed=(pushed+al-1)/al*al;
+ }
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[t2],mregnames[sp],pushed+minframe-b);
+ pushed+=size;
+ size=zm2l(p->z.val.vmax);
+ }else{
+ p->z.val.vmax=zmsub(p->z.val.vmax,l2zm((long)b));
+ load_address(f,t2,&p->z,POINTER);
+ p->z.val.vmax=zmsub(p->z.val.vmax,l2zm((long)b));
+ }
+ }
+ BSET(regs_modified,t1);
+ BSET(regs_modified,t2);
+ BSET(regs_modified,t3);
+ if(optspeed)
+ l=size/(8*b);
+ else
+ l=size/b;
+ if(l>1){
+ if(hi(l)){
+ emit(f,"\tlis\t%s,%lu\n",mregnames[t3],(l>>16)&65535);
+ emit(f,"\tori\t%s,%s,%lu\n",mregnames[t3],mregnames[t3],l&65535);
+ }else{
+ emit(f,"\tli\t%s,%ld\n",mregnames[t3],lo(l));
+ }
+ emit(f,"\tmtctr\t%s\n",mregnames[t3]);
+ BSET(regs_modified,ctr);
+ emit(f,"%s%d:\n",labprefix,++label);
+ }
+ if(l>0){
+ for(i=b;optspeed&&i<=7*b;i+=b){
+ emit(f,"\tl%s\t%s,%d(%s)\n",ld,mregnames[t3],i,mregnames[t1]);
+ emit(f,"\tst%s\t%s,%d(%s)\n",st,mregnames[t3],i,mregnames[t2]);
+ }
+ emit(f,"\tl%su\t%s,%d(%s)\n",ld,mregnames[t3],i,mregnames[t1]);
+ emit(f,"\tst%su\t%s,%d(%s)\n",st,mregnames[t3],i,mregnames[t2]);
+
+ }
+ if(l>1){
+ emit(f,"\tbdnz\t%s%d\n",labprefix,label);
+ }
+ if(optspeed)
+ size=size%(8*b);
+ else
+ size=size%b;
+ for(i=0;i<size/b;i++){
+ emit(f,"\tl%su\t%s,%d(%s)\n",ld,mregnames[t3],b,mregnames[t1]);
+ emit(f,"\tst%su\t%s,%d(%s)\n",st,mregnames[t3],b,mregnames[t2]);
+ }
+ size=size%b;i=b;
+ if(size&2){
+ emit(f,"\tl%su\t%s,%d(%s)\n",ldt(SHORT),mregnames[t3],b,mregnames[t1]);
+ emit(f,"\tst%su\t%s,%d(%s)\n",sdt(SHORT),mregnames[t3],b,mregnames[t2]);
+ i=2;
+ }
+ if(size&1){
+ emit(f,"\tl%su\t%s,%d(%s)\n",ldt(CHAR),mregnames[t3],i,mregnames[t1]);
+ emit(f,"\tst%su\t%s,%d(%s)\n",sdt(CHAR),mregnames[t3],i,mregnames[t2]);
+ }
+ p->z.flags=0;
+ continue;
+ }
+ if(c==TEST&&ISFLOAT(t)){
+ p->code=c=COMPARE;
+ p->q2.flags=KONST;
+ p->q2.val.vldouble=d2zld(0.0);
+ if((t&NQ)==DOUBLE) p->q2.val.vdouble=zld2zd(p->q2.val.vldouble);
+ if((t&NQ)==FLOAT) p->q2.val.vfloat=zld2zf(p->q2.val.vldouble);
+ }
+ p=do_refs(f,p);
+ c=p->code;
+ setcc=p->ext.setcc;
+ if(c==SUBPFP) c=SUB;
+ if(c==ADDI2P) c=ADD;
+ if(c==SUBIFP) c=SUB;
+ if(c==CONVERT){
+ int to;
+ static struct obj o;char *ip;
+ long moff;int offreg;
+ to=p->typf2;
+ if(ISFLOAT(to)){
+ if(ISFLOAT(t)){
+ zreg=q1reg;
+ continue;
+ }
+ if(tmpoff>32767){
+ moff=0;offreg=t1;
+ emit(f,"\taddis\t%s,%s,%ld\n",mregnames[offreg],mregnames[sp],hi(tmpoff));
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[offreg],mregnames[offreg],lo(tmpoff));
+ }else{
+ moff=tmpoff;
+ offreg=sp;
+ }
+ if((t&NU)==(UNSIGNED|INT)||(t&NU)==(UNSIGNED|LONG)){
+ o.flags=KONST;
+ ip=(char *)&o.val.vdouble;
+ ip[0]=0x41;
+ ip[1]=0xe0;
+ ip[2]=0x00;
+ ip[3]=0x00;
+ ip[4]=0x00;
+ ip[5]=0x00;
+ ip[6]=0x00;
+ ip[7]=0x00;
+ load_reg(f,f2,&o,DOUBLE,t2);
+ emit(f,"\tfcmpu\t%s,%s,%s\n",mregnames[cr0],mregnames[q1reg],mregnames[f2]);
+ emit(f,"\tcror\t3,2,1\n");
+ emit(f,"\tbso\t%s,%s%d\n",mregnames[cr0],labprefix,++label);
+ emit(f,"\tfctiwz\t%s,%s\n",mregnames[f2],mregnames[q1reg]);
+ emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(DOUBLE),mregnames[f2],moff-8,mregnames[offreg]);
+ emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(t&NQ),mregnames[zreg],moff-zm2l(sizetab[t&NQ]),mregnames[offreg]);
+ emit(f,"\tb\t%s%d\n",labprefix,++label);
+ emit(f,"%s%d:\n",labprefix,label-1);
+ emit(f,"\tfsub\t%s,%s,%s\n",mregnames[f2],mregnames[q1reg],mregnames[f2]);
+ emit(f,"\tfctiwz\t%s,%s\n",mregnames[f2],mregnames[f2]);
+ emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(DOUBLE),mregnames[f2],moff-8,mregnames[offreg]);
+ emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(INT),mregnames[zreg],moff-zm2l(sizetab[t&NQ]),mregnames[offreg]);
+ emit(f,"\txoris\t%s,%s,32768\n",mregnames[zreg],mregnames[zreg]);
+ emit(f,"%s%d:\n",labprefix,label);
+ BSET(regs_modified,f2);
+ BSET(regs_modified,zreg);
+ BSET(regs_modified,q1reg);
+ }else{
+ emit(f,"\tfctiwz\t%s,%s\n",mregnames[f3],mregnames[q1reg]);
+ emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(DOUBLE),mregnames[f3],moff-8,mregnames[offreg]);
+ emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(t&NQ),mregnames[zreg],moff-zm2l(sizetab[t&NQ]),mregnames[offreg]);
+ BSET(regs_modified,f3);
+ BSET(regs_modified,zreg);
+ BSET(regs_modified,q1reg);
+ }
+ if(t==CHAR) emit(f,"\textsb\t%s,%s\n",mregnames[zreg],mregnames[zreg]);
+ continue;
+ }
+ if(ISFLOAT(t)){
+ if(tmpoff>32767){
+ moff=0;offreg=t1;
+ if(q1reg==t1){
+ emit(f,"\tmr\t%s,%s\n",mregnames[t3],mregnames[q1reg]);
+ q1reg=t3;
+ BSET(regs_modified,t3);
+ }
+ emit(f,"\taddis\t%s,%s,%ld\n",mregnames[offreg],mregnames[sp],hi(tmpoff));
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[offreg],mregnames[offreg],lo(tmpoff));
+ }else{
+ moff=tmpoff;
+ offreg=sp;
+ }
+ o.flags=KONST;
+ ip=(char *)&o.val.vdouble;
+ ip[0]=0x43;
+ ip[1]=0x30;
+ ip[2]=0x00;
+ ip[3]=0x00;
+ ip[4]=0x80;
+ ip[5]=0x00;
+ ip[6]=0x00;
+ ip[7]=0x00;
+ if((to&NU)==(UNSIGNED|INT)||(to&NU)==(UNSIGNED|LONG)){
+ ip[4]=0x00;
+ load_reg(f,f2,&o,DOUBLE,t2);
+ emit(f,"\tlis\t%s,17200\n",mregnames[t2]);
+ emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(INT),mregnames[q1reg],moff-4,mregnames[offreg]);
+ emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(INT),mregnames[t2],moff-8,mregnames[offreg]);
+ emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(DOUBLE),mregnames[zreg],moff-8,mregnames[offreg]);
+ emit(f,"\tfsub\t%s,%s,%s\n",mregnames[zreg],mregnames[zreg],mregnames[f2]);
+ }else{
+ emit(f,"\tlis\t%s,17200\n",mregnames[t2]);
+ emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(INT),mregnames[t2],moff-8,mregnames[offreg]);
+ emit(f,"\txoris\t%s,%s,32768\n",mregnames[t2],mregnames[q1reg]);
+ emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(INT),mregnames[t2],moff-4,mregnames[offreg]);
+ emit(f,"\tl%s\t%s,%ld(%s)\n",ldt(DOUBLE),mregnames[zreg],moff-8,mregnames[offreg]);
+ load_reg(f,f2,&o,DOUBLE,t2);
+ emit(f,"\tfsub\t%s,%s,%s\n",mregnames[zreg],mregnames[zreg],mregnames[f2]);
+ }
+ continue;
+ }
+ if((t&NQ)>=(to&NQ)){
+ if((to&NU)==CHAR){
+ emit(f,"\textsb%s\t%s,%s\n",record[setcc],mregnames[zreg],mregnames[q1reg]);
+ ccset|=setcc;
+ }else if((to&NU)==SHORT&&!q1loaded){
+ emit(f,"\textsh%s\t%s,%s\n",record[setcc],mregnames[zreg],mregnames[q1reg]);
+ ccset|=setcc;
+ }else if((to&NU)==(UNSIGNED|CHAR)&&!q1loaded){
+ emit(f,"\tclrlwi%s\t%s,%s,24\n",record[setcc],mregnames[zreg],mregnames[q1reg]);
+ ccset|=setcc;
+ }else if((to&NU)==(UNSIGNED|SHORT)&&!q1loaded){
+ emit(f,"\tclrlwi%s\t%s,%s,16\n",record[setcc],mregnames[zreg],mregnames[q1reg]);
+ ccset|=setcc;
+ }else{
+ if(setcc){
+ emit(f,"\tmr.\t%s,%s\n",mregnames[zreg],mregnames[q1reg]);
+ ccset=1;
+ }else{
+ zreg=q1reg;
+ }
+ }
+ continue;
+ }else{
+ zreg=q1reg;
+ continue;
+ }
+ }
+ if(c==KOMPLEMENT){
+ emit(f,"\tnor%s\t%s,%s,%s\n",record[setcc],mregnames[zreg],mregnames[q1reg],mregnames[q1reg]);
+ ccset|=setcc;
+ continue;
+ }
+ if(ISFLOAT(t)) {fpp="f";fpf=1;} else {fpp="";fpf=0;}
+ if(c==SETRETURN){
+ if(p->z.reg){
+ if((t&NU)==CHAR)
+ emit(f,"\textsb\t%s,%s\n",mregnames[p->z.reg],mregnames[q1reg]);
+ else if(!q1loaded&&(t&NU)==SHORT)
+ emit(f,"\textsh\t%s,%s\n",mregnames[p->z.reg],mregnames[q1reg]);
+ else if(!q1loaded&&(t&NU)==(UNSIGNED|CHAR))
+ emit(f,"\tclrlwi\t%s,%s,24\n",mregnames[p->z.reg],mregnames[q1reg]);
+ else if(!q1loaded&&(t&NU)==(UNSIGNED|SHORT))
+ emit(f,"\tclrlwi\t%s,%s,16\n",mregnames[p->z.reg],mregnames[q1reg]);
+ else if(p->z.reg!=q1reg)
+ emit(f,"\t%smr\t%s,%s\n",fpp,mregnames[p->z.reg],mregnames[q1reg]);
+ BSET(regs_modified,p->z.reg);
+ }else
+ ierror(0);
+ continue;
+ }
+ if(c==GETRETURN){
+ if(p->q1.reg)
+ zreg=p->q1.reg;
+ else
+ p->z.flags=0;
+ continue;
+ }
+ if(c==CALL){
+ ccset=0;
+ if(stack_valid){
+ int i;
+ if(p->call_cnt<=0){
+ err_ic=p;error(320);
+ stack_valid=0;
+ v->fi->flags|=(WARNED_STACK|WARNED_REGS);
+ }
+ for(i=0;i<p->call_cnt;i++){
+ if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_STACK)){
+ if(framesize+zum2ul(p->call_list[i].v->fi->stack1)>stack)
+ stack=framesize+zum2ul(p->call_list[i].v->fi->stack1);
+ }else{
+ err_ic=p;
+ if(!p->call_list[i].v->fi) p->call_list[i].v->fi=new_fi();
+ if(!(p->call_list[i].v->fi->flags&WARNED_STACK)){
+ error(317,p->call_list[i].v->identifier);
+ p->call_list[i].v->fi->flags|=WARNED_STACK;
+ }
+ v->fi->flags|=WARNED_STACK;
+ stack_valid=0;
+ }
+#if HAVE_OSEK
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ }
+ }
+ if(!calc_regs(p,f!=0)&&v->fi) all_regs=0;
+#if HAVE_OSEK
+/* removed */
+/* removed */
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ }else{
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR){
+ if(!strcmp("__va_start",p->q1.v->identifier)){
+ emit(f,"\taddi\t%s,%s,%lu\n",mregnames[r3],mregnames[sp],framesize+minframe+zm2l(va_offset(v))/*+vparmos*/);
+ BSET(regs_modified,r3);continue;
+ }
+ if(!strcmp("__va_regbase",p->q1.v->identifier)){
+ emit(f,"\taddi\t%s,%s,%ld\n",mregnames[r3],mregnames[sp],regbase);
+ BSET(regs_modified,r3);continue;continue;
+ }
+ if(!strcmp("__va_fixedgpr",p->q1.v->identifier)){
+ emit(f,"\tli\t%s,%d\n",mregnames[r3],fixedgpr);
+ BSET(regs_modified,r3);continue;continue;
+ }
+ if(!strcmp("__va_fixedfpr",p->q1.v->identifier)){
+ emit(f,"\tli\t%s,%d\n",mregnames[r3],fixedfpr);
+ BSET(regs_modified,r3);continue;continue;
+ }
+ }
+ if(g_flags[10]&USEDFLAG) emit(f,"\tcreqv\t6,6,6\n");
+ /* poweropen-hack! look if some fp-args have been passed on the stack */
+ if(POWEROPEN&&!zmeqto(p->q2.val.vmax,l2zm(0L))){
+ int r=45/*f12*/,off=24;
+ for(i=0;r<47&&i<p->arg_cnt;i++){
+ if(p->arg_list[i]->code==PUSH){
+ int typ=p->arg_list[i]->typf;
+ if(ISFLOAT(typ)){
+ emit(f,"\tl%s\t%s,%d(%s)\n",ldt(typ&NQ),mregnames[r],off,mregnames[sp]);
+ r++;
+ }
+ }
+ off+=(zm2l(p->arg_list[i]->q2.val.vmax)+3)/4*4;
+ }
+ }
+ if(q1reg){
+ emit(f,"\tmtlr\t%s\n",mregnames[q1reg]);
+ emit(f,"\tblrl\n");
+ }else{
+ emit(f,"\tbl\t");emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ BSET(regs_modified,lr);
+ }
+ pushed-=zm2l(p->q2.val.vmax);
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(t==0) ierror(0);
+ if(q1reg||c==PUSH){
+ if(c==PUSH){
+ pushed=(pushed+3)/4*4;
+ if(align_arguments&&malign[p->typf&NQ]==8)
+ pushed=(pushed+7)/8*8;
+ if(q1reg)
+ emit(f,"\tst%s\t%s,%ld(%s)\n",sdt(t&NQ),mregnames[q1reg],pushed+minframe,mregnames[sp]);
+ pushed+=zm2l(p->q2.val.vmax);
+ continue;
+ }
+ if(c==ASSIGN){
+ if(setcc&&!fpf&&sizetab[t&NQ]==sizetab[INT]){
+ emit(f,"\tmr.\t%s,%s\n",mregnames[zreg],mregnames[q1reg]);
+ ccset=1;
+ }else{
+ zreg=q1reg;
+ }
+ }
+ continue;
+ }
+ }
+ if(c==ADDRESS){
+ load_address(f,zreg,&p->q1,POINTER);
+ continue;
+ }
+ if(c==MINUS){
+ emit(f,"\t%sneg%s\t%s,%s\n",fpp,record[setcc&&!fpf],mregnames[zreg],mregnames[q1reg]);
+ if(setcc&&!fpf) ccset=1;
+ continue;
+ }
+ if(c==TEST){
+ if(!(p->z.flags®))
+ p->z.reg=cr0;
+ if(!multiple_ccs&&(t&UNSIGNED)){
+ struct IC *p2=p->next;
+ while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG)) p2=p2->next;
+ if(!p2) continue;
+ if(p2->code==BGT) p2->code=BNE;
+ else if(p2->code==BGE) p2->code=BRA;
+ else if(p2->code==BLT) p2->code=NOP;
+ else if(p2->code==BLE) p2->code=BEQ;
+ }
+ if(ccset&&p->z.reg==cr0) continue;
+ if(ISFLOAT(t)){
+ ierror(0);
+ }else{
+ if((t&NU)==CHAR)
+ emit(f,"\textsb.\t%s,%s\n",mregnames[p->z.reg],mregnames[q1reg]);
+ else if((t&NU)==SHORT)
+ emit(f,"\textsh.\t%s,%s\n",mregnames[p->z.reg],mregnames[q1reg]);
+ else if((t&NU)==(UNSIGNED|CHAR))
+ emit(f,"\tandi.\t%s,%s,255\n",mregnames[p->z.reg],mregnames[q1reg]);
+ else if((t&NU)==(UNSIGNED|SHORT))
+ emit(f,"\tandi.\t%s,%s,65535\n",mregnames[p->z.reg],mregnames[q1reg]);
+ else
+ emit(f,"\tcmp%swi\t%s,%s,0\n",(t&UNSIGNED)?"l":"",mregnames[p->z.reg],mregnames[q1reg]);
+ }
+ if(p->z.reg==cr0) ccset=0;
+ continue;
+ }
+ if(c==COMPARE){
+ if(!(p->z.flags®))
+ p->z.reg=cr0;
+ if(ISFLOAT(t))
+ emit(f,"\tfcmpu\t%s,%s,",mregnames[p->z.reg],mregnames[q1reg]);
+ else
+ emit(f,"\tcmp%sw%s\t%s,%s,",((t&UNSIGNED)||((t&NQ)==POINTER))?"l":"",isimm[q2reg==0],mregnames[p->z.reg],mregnames[q1reg]);
+ emit_obj(f,&p->q2,t);emit(f,"\n");
+ if(p->z.reg==cr0) ccset=0;
+ continue;
+ }
+ BSET(regs_modified,zreg);
+ if(c==AND&&q2reg==0){
+ ccset=setcc;
+ emit(f,"\tandi.\t%s,%s,",mregnames[zreg],mregnames[q1reg]);
+ emit_obj(f,&p->q2,t|UNSIGNED);emit(f,"\n");
+ continue;
+ }
+ if(c>=OR&&c<=AND){
+ emit(f,"\t%s%s%s\t%s,%s,",logicals[c-OR],isimm[q2reg==0],record[setcc&&q2reg],mregnames[zreg],mregnames[q1reg]);
+ emit_obj(f,&p->q2,t|UNSIGNED);emit(f,"\n");
+ if(setcc&&q2reg) ccset=1;
+ continue;
+ }
+ if(c==SUB&&(p->q1.flags&KONST)){
+ emit(f,"\tsubfic\t%s,%s,",mregnames[zreg],mregnames[q2reg]);
+ emit_obj(f,&p->q1,t&NQ);emit(f,"\n");
+ continue;
+ }
+ if(c>=LSHIFT&&c<=MOD){
+ if(c==RSHIFT&&((t&NQ)<=SHORT)){
+ /* special treatment for short shifts used in bitfields with
+ sub-int type; will not handle the general case (which, however,
+ should never occur) */
+ int width,shift;
+ width=sizetab[t&NQ]*8;
+ if(!(p->q2.flags&KONST)) ierror(0);
+ eval_const(&p->q2.val,p->typf2&NU);
+ shift=zm2l(vmax);
+ if(shift<0||shift>=width) ierror(0);
+ if(shift==0) continue;
+ if(!(t&UNSIGNED)){
+ emit(f,"\texts%c\t%s,%s\n",width==8?'b':'h',mregnames[zreg],mregnames[q1reg]);
+ q1reg=zreg;
+ }
+ emit(f,"\trlwinm\t%s,%s,%d,%d,%d\n",mregnames[zreg],mregnames[q1reg],32-shift,32-width+((t&UNSIGNED)?shift:0),31);
+ continue;
+ }
+ if(c==RSHIFT&&!(t&UNSIGNED)){
+ emit(f,"\tsraw%s%s\t%s,%s,",isimm[q2reg==0],record[setcc],mregnames[zreg],mregnames[q1reg]);
+ emit_obj(f,&p->q2,q2typ(p));
+ /* fix for illegal shift values (undefined behaviour) */
+ if(!isreg(q2))
+ emit(f,"&31");
+ emit(f,"\n");
+ ccset|=setcc;
+ continue;
+ }
+ if(c==MOD){
+ i=0;
+ if(zreg==q1reg||zreg==q2reg){
+ if(t1!=q1reg&&t1!=q2reg) i=t1;
+ if(t2!=q1reg&&t2!=q2reg) i=t2;
+ }else i=zreg;
+ if(i==0||i==q1reg||i==q2reg) ierror(0);
+ emit(f,"\tdivw%s\t%s,%s,%s\n",(t&UNSIGNED)?"u":"",mregnames[i],mregnames[q1reg],mregnames[q2reg]);
+ emit(f,"\tmullw\t%s,%s,%s\n",mregnames[i],mregnames[i],mregnames[q2reg]);
+ emit(f,"\tsubf%s\t%s,%s,%s\n",record[setcc],mregnames[zreg],mregnames[i],mregnames[q1reg]);
+ ccset|=setcc;
+ continue;
+ }
+ if(c==DIV&&(t&UNSIGNED)){
+ emit(f,"\tdivwu%s%s\t%s,%s,",isimm[q2reg==0],record[setcc&&q2reg],mregnames[zreg],mregnames[q1reg]);
+ if(setcc&&q2reg) ccset=1;
+ }else if(c==MULT&&ISFLOAT(t)){
+ if(isreg(z)&&(g_flags[14]&USEDFLAG)){
+ struct IC *np=p->next,*add;int madd;
+ while(np&&(np->code==FREEREG||np->code==ALLOCREG)) np=np->next;
+ if(np&&(np->code==ADD||np->code==SUB)&&(np->q1.flags&(REG|DREFOBJ))==REG&&(np->q1.reg==p->z.reg||(np->code==ADD&&np->q2.reg==p->z.reg))&&(np->q2.flags&(REG|DREFOBJ))==REG&&np->q1.reg!=np->q2.reg){
+ add=np;
+ madd=0;
+ if((np->z.flags&(REG|DREFOBJ))==REG&&np->z.reg==p->z.reg) madd=1;
+ np=np->next;
+ while(np&&(np->code==FREEREG||np->code==ALLOCREG)){
+ if(np->code==FREEREG&&np->q1.reg==p->z.reg) madd=1;
+ np=np->next;
+ }
+ if(madd){
+ if((add->z.flags&(REG|DREFOBJ))==REG) zreg=add->z.reg;
+ if(add->code==ADD){
+ if(add->q1.reg==p->z.reg) madd=add->q2.reg; else madd=add->q1.reg;
+ emit(f,"\tfmadd%s\t%s,%s,%s,%s\n",(t&NQ)==FLOAT?"s":"",mregnames[zreg],mregnames[q1reg],mregnames[q2reg],mregnames[madd]);
+ }else
+ emit(f,"\tfmsub%s\t%s,%s,%s,%s\n",(t&NQ)==FLOAT?"s":"",mregnames[zreg],mregnames[q1reg],mregnames[q2reg],mregnames[add->q2.reg]);
+ add->code=NOP;
+ p->z=add->z;
+ add->z.am=0;
+ continue;
+ }
+ }
+ }
+ emit(f,"\tfmul%s\t%s,%s,",(t&NQ)==FLOAT?"s":"",mregnames[zreg],mregnames[q1reg]);
+ }else if(c==DIV&&ISFLOAT(t)){
+ emit(f,"\tfdiv%s\t%s,%s,",(t&NQ)==FLOAT?"s":"",mregnames[zreg],mregnames[q1reg]);
+ }else if(c==MULT&&q2reg==0){
+ emit(f,"\tmulli\t%s,%s,",mregnames[zreg],mregnames[q1reg]);
+ }else if(c==ADD&&setcc&&!q2reg){
+ emit(f,"\taddic.\t%s,%s,",mregnames[zreg],mregnames[q1reg]);
+ ccset=1;
+ }else{
+ emit(f,"\t%s%s%s%s%s\t%s,%s,",fpp,arithmetics[c-LSHIFT],(t&NQ)==FLOAT?"s":"",isimm[q2reg==0],record[setcc&&q2reg&&!fpf],mregnames[zreg],mregnames[q1reg]);
+ if(setcc&&q2reg&&!fpf) ccset=1;
+ }
+ emit_obj(f,&p->q2,q2typ(p)&NQ);
+ /* fix for illegal shift values (undefined behaviour) */
+ if((c==LSHIFT||c==RSHIFT)&&q2reg==0) emit(f,"&31");
+ emit(f,"\n");
+ continue;
+ }
+ pric2(stdout,p);
+ ierror(0);
+ }
+ if(!cross_module) lastlabel=label; /*FIXME*/
+ free(once);free(twice);
+ function_bottom(f,v,of);
+#if HAVE_OSEK
+/* removed */
+#endif
+ if(stack_valid){
+ if(!v->fi) v->fi=new_fi();
+ if(v->fi->flags&ALL_STACK){
+ if(v->fi->stack1!=stack&&!(v->tattr&SAVEALL))
+ if(f) error(319,"",stack,v->fi->stack1);
+#if HAVE_OSEK
+/* removed */
+/* removed */
+/* removed */
+#endif
+ }else{
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=stack;
+ }
+ }
+ emit(f,"# stacksize=%lu%s\n",(unsigned long)stack,stack_valid?"":"+??");
+ if(stack_valid) emit(f,"\t.set\t%s__stack_%s,%lu\n",idprefix,v->identifier,(unsigned long)stack);
+ if(debug_info){
+ emit(f,"%s%d:\n",labprefix,++label);
+ dwarf2_function(f,v,label);
+ if(f) section=-1;
+ }
+}
+
+int shortcut(int code,int typ)
+{
+ return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *ft)
+{
+#if HAVE_AOS4
+ extern int aos4_attr(struct Typ *,char *);
+#endif
+ int f;
+ if(!m) ierror(0);
+ if(!t) ierror(0);
+ if(vararg&&POWEROPEN) return 0;
+#ifdef HAVE_AOS4
+ if(vararg&&ft&&aos4_attr(ft,"linearvarargs")) return 0;
+#endif
+ f=t->flags&NQ;
+ if(f<=LONG||f==POINTER){
+ if(m->gregs>=8) return 0;
+ if(POWEROPEN){
+ if(!STORMC) m->fregs++;
+ return -(r3+m->gregs++);
+ }else{
+ return r3+m->gregs++;
+ }
+ }
+ if(f==LLONG){
+ int r;
+ if(m->gregs>=7) return 0;
+ m->gregs=(m->gregs+3)/2*2;
+ if(m->gregs==2) r=74;
+ else if(m->gregs==4) r=75;
+ else if(m->gregs==6) r=76;
+ else if(m->gregs==8) r=77;
+ else ierror(0);
+ if(POWEROPEN)
+ return -r;
+ else
+ return r;
+ }
+ if(ISFLOAT(f)){
+ if(POWEROPEN){
+ if(m->fregs>=11) return 0; /* hack! we pretend fp-arg 12/13 is passed on the stack */
+ if(!STORMC){
+ if(f!=FLOAT) m->gregs+=2; else m->gregs++;
+ }
+ return -(34+m->fregs++);
+ }else{
+ if(m->fregs>=8) return 0;
+ return 34+m->fregs++;
+ }
+ }
+ return 0;
+}
+
+int handle_pragma(const char *s)
+{
+ if(!strncmp("amiga-align",s,11)){
+ align[INT]=align[LONG]=align[LLONG]=align[POINTER]=align[FLOAT]=align[DOUBLE]=align[LDOUBLE]=l2zm(2L);
+ return 1;
+ }else if(!strncmp("natural-align",s,13)){
+ align[INT]=align[LONG]=align[POINTER]=align[FLOAT]=l2zm(4L);
+ align[LLONG]=align[DOUBLE]=align[LDOUBLE]=l2zm(8L);
+ return 1;
+ }else if(!strncmp("default-align",s,13)){
+ if(g_flags[7]&USEDFLAG){
+ align[INT]=align[LONG]=align[LLONG]=align[POINTER]=align[FLOAT]=align[DOUBLE]=align[LDOUBLE]=l2zm(2L);
+ }else{
+ align[INT]=align[LONG]=align[POINTER]=align[FLOAT]=l2zm(4L);
+ align[LLONG]=align[DOUBLE]=align[LDOUBLE]=l2zm(8L);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+void cleanup_cg(FILE *f)
+{
+ struct fpconstlist *p;
+ unsigned char *ip;
+ struct StatFPtrList *tfp,*fp=firstfptr;
+
+ title(f);
+
+ if(fp){
+ emit(f,tocname);
+ if(f) section=TOC;
+ }
+ while(tfp=fp){
+ emit(f,"%s%s%ld:\n\t.long\t%s%ld\n",
+ tocprefix,labprefix,zm2l(tfp->vptr->offset),
+ labprefix,zm2l(tfp->vptr->offset));
+ fp=fp->next;
+ free(tfp);
+ }
+ if(f&&stack_check)
+ emit(f,"\t.global\t%s__stack_check\n",idprefix);
+ while(p=firstfpc){
+ if(f){
+ if(POWEROPEN&&!use_sd(p->typ)){
+ emit(f,tocname);
+ emit(f,"%s%s%ld:\n",tocprefix,labprefix,zm2l(p->label));
+ emit(f,"\t.long\t%s%ld\n",labprefix,zm2l(p->label));
+ if(f) section=TOC;
+ }
+ if(use_sd(p->typ)){
+ if(EABI){
+ if(section!=SDATA2){emit(f,sdata2name);if(f) section=SDATA2;}
+ }else{
+ if(section!=TOC){emit(f,tocname);if(f) section=TOC;}
+ }
+ }else{
+ if(section!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ }
+ if((p->typ&NQ)==DOUBLE)
+ emit(f,"\t.align\t3\n");
+ else
+ emit(f,"\t.align\t2\n");
+ emit(f,"%s%d:\n\t.long\t",labprefix,p->label);
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ if((p->typ&NQ)==DOUBLE){
+ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ emit(f,"\n");
+ }
+ firstfpc=p->next;
+ free(p);
+ }
+}
+void cleanup_db(FILE *f)
+{
+ dwarf2_cleanup(f);
+ if(f) section=-1;
+}
+/* mark instructions which can (probably) be implemented with faster
+ machine-code than the IC migh suggest, e.g. an addition which can
+ be merged with a load bz use of target addressing-modes;
+ the optimizer should hesitate to modifz such instructions if it's not
+ a definite win */
+
+static int is_single_eff_ic(struct IC *p)
+{
+ struct Var *v;
+ if(p->code!=ADDI2P&&p->code!=SUBIFP)
+ return 0;
+ if(!(p->q2.flags&KONST)){
+ if(CONSERVATIVE_SR){
+ if((p->q2.flags&(VAR|DREFOBJ))!=VAR)
+ return 0;
+ if(p->q2.v->storage_class==STATIC||p->q2.v->storage_class==EXTERN)
+ return 0;
+ }else
+ return 0;
+ }
+ if((p->q1.flags&(VAR|DREFOBJ))!=VAR)
+ return 0;
+ if(p->q1.v->storage_class==STATIC||p->q1.v->storage_class==EXTERN)
+ return 0;
+ if((p->z.flags&(VAR|DREFOBJ))!=VAR)
+ return 0;
+ if(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)
+ return 0;
+ v=p->z.v;
+ for(p=p->next;p;p=p->next){
+ int c=p->code;
+ if(c==LABEL||(c>=BEQ&&c<=BRA))
+ return 0;
+ if((p->q1.flags&VAR)&&p->q1.v==v){
+ if(p->q1.flags&DREFOBJ)
+ return 1;
+ else
+ return 0;
+ }
+ if((p->q2.flags&VAR)&&p->q2.v==v){
+ if(p->q2.flags&DREFOBJ)
+ return 1;
+ else
+ return 0;
+ }
+ if((p->z.flags&VAR)&&p->z.v==v){
+ if(p->z.flags&DREFOBJ)
+ return 1;
+ else
+ return 0;
+ }
+ }
+}
+void mark_eff_ics(void)
+{
+ struct IC *p;
+ for(p=first_ic;p;p=p->next){
+ if(is_single_eff_ic(p))
+ p->flags|=EFF_IC;
+ else
+ p->flags&=~EFF_IC;
+ }
+}
+
+char *use_libcall(int c,int t,int t2)
+{
+ static char fname[32];
+ char *ret=0;
+
+ if(OLDLIBCALLS) return 0;
+
+ if((t&NQ)==LLONG){
+ ret=fname;
+ if(c==MULT)
+ sprintf(fname,"__mulint64");
+ else if(c==DIV)
+ sprintf(fname,"__div%cint64",(t&UNSIGNED)?'u':'s');
+ else if(c==MOD)
+ sprintf(fname,"__mod%cint64",(t&UNSIGNED)?'u':'s');
+ else if(c==RSHIFT)
+ sprintf(fname,"__rsh%cint64",(t&UNSIGNED)?'u':'s');
+ else if(c==LSHIFT)
+ sprintf(fname,"__lshint64");
+ else
+ ret=0;
+ }
+ return ret;
+}
+
+
+
+#if HAVE_OSEK
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
diff --git a/machines/ppc/machine.dt b/machines/ppc/machine.dt
new file mode 100755
index 0000000..526c8d4
--- /dev/null
+++ b/machines/ppc/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/ppc/machine.h b/machines/ppc/machine.h
new file mode 100755
index 0000000..f02654c
--- /dev/null
+++ b/machines/ppc/machine.h
@@ -0,0 +1,137 @@
+/* Example of a code-generator for a PowerPC */
+
+#include "dt.h"
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Not used in this code-generrator. */
+struct AddressingMode{
+ int flags;
+ int base;
+ long offset;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR 87
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 30
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P INT
+
+/* This specifies the largest integer type that can be added to a */
+/* pointer. */
+#define MAXADDI2P LONG
+
+#define HAVE_INT_SIZET 1
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 1
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 0
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 256
+
+/* Parameters are sometimes passed in registers without __reg. */
+#define HAVE_REGPARMS 1
+
+/* Parameters on the stack should be pushed in order rather than */
+/* in reverse order. */
+#define ORDERED_PUSH 1
+
+/* Structure for reg_parm(). */
+struct reg_handle{
+ unsigned long gregs;
+ unsigned long fregs;
+};
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/* We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/* we have a mark_eff_ics function */
+#define HAVE_TARGET_EFF_IC 1
+
+/* we have register-pairs */
+#define HAVE_REGPAIRS 1
+
+#define JUMP_TABLE_DENSITY 0.8
+#define JUMP_TABLE_LENGTH 12
+
+/* This type will be added to every IC. Can be used by the cg. */
+#define HAVE_EXT_IC 1
+struct ext_ic {
+ int setcc;
+};
+
+/* OSEK support */
+#define HAVE_OSEK 1
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+/* support for variable-length arrays */
+#define ALLOCVLA_REG 4
+#if 0
+#define ALLOCVLA_INLINEASM "\tlwz\t0,0(1)\n"\
+ "\taddi\t3,3,7\n"\
+ "\tsrwi\t3,3,3\n"\
+ "\tslwi\t3,3,3\n"\
+ "\tneg\t11,3\n"\
+ "\tsub\t3,1,3\n"\
+ "\tsubi\t11,11,8\n"\
+ "\tstwux\t0,1,11"
+#endif
+#define ALLOCVLA_INLINEASM "\tlwz\t0,0(1)\n"\
+ "\tneg\t3,3\n"\
+ "\tsrwi\t3,3,3\n"\
+ "\tslwi\t3,3,3\n"\
+ "\tstwux\t0,1,3\n"\
+ "\taddi\t3,1,____fo"
+#define FREEVLA_REG 6
+#define FREEVLA_INLINEASM "\tlwz\t0,0(1)\n"\
+ "\tmr\t1,5\n"\
+ "\tstw\t0,0(1)"
+#define OLDSPVLA_INLINEASM "\tmr\t3,1"
+#define FPVLA_REG 32
diff --git a/machines/ppc/schedule.c b/machines/ppc/schedule.c
new file mode 100755
index 0000000..e7172d3
--- /dev/null
+++ b/machines/ppc/schedule.c
@@ -0,0 +1,1158 @@
+/*
+ * vscppc
+ *
+ * vbcc PowerPC scheduler
+ * (C)1998-2001 by Frank Wille <frank@phoenix.owl.de>
+ *
+ * vscppc is freeware and part of the portable and retargetable ANSI C
+ * compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
+ * vscppc may be freely redistributed as long as no modifications are
+ * made and nothing is charged for it. Non-commercial usage is allowed
+ * without any restrictions.
+ * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
+ * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
+ *
+ * History:
+ * V0.5 14-Feb-01
+ * FSCPR is no longer marked as used/modified, which allows the
+ * scheduler to rearrange all FPU instructions. As a consequence, the
+ * only instruction reading FPSCR, mffs, has to be marked as barrier.
+ * V0.4 01-Dec-99
+ * 603e PID7 seems to have a latency of 20 instead 37 for
+ * the "div" instruction (source: Michal Bartczak).
+ * V0.3b 30-Jul-98
+ * crxxx instructions used/modified wrong CCRs.
+ * V0.3a 21-Jul-98
+ * "la" instruction was not recognized.
+ * V0.3 20-Jul-98
+ * Target-specific options via sched_option() removed. Options
+ * are passed in the assembler source, e.g. "#vsc elf".
+ * Differentiation between 603 and 604 (selected by "#vsc cpu").
+ * Now, scheduling takes place with regard to the real PowerPC
+ * architecture.
+ * V0.2 12-Jul-98
+
+ * Option "-elf" lets the scheduler accept ELF/SVR4 sources,
+ * which only use numbers instead of full register names.
+ * Target-specific options require a modification in the
+ * portable scheduler part vsc.c.
+ * V0.1 10-Jul-98
+ * vscppc seems to be stable, after some tests.
+ * However, it still needs a lot of fine tuning (my PowerPC
+ * docs are at home).
+ * A differentiation between the PPC CPUs (603e, 604e) is missing.
+ * V0.0 09-Jul-98
+ * File created.
+ *
+ */
+
+#include "vsc.h"
+
+char tg_copyright[]="PowerPC scheduler V0.5 (c) in 1998-2001 by Frank Wille";
+
+static int elf=0,cpu=604;
+
+
+
+int sched_init(void)
+{
+ return (1);
+}
+
+
+void sched_cleanup(void)
+{
+}
+
+
+static void sched_option(char *s)
+{
+ if (!strncmp(s,"elf",3)) {
+ elf = 1;
+ }
+ else if (!strncmp(s,"cpu ",4)) {
+ if (!strncmp(s+4,"603",3))
+ cpu = 603;
+ else if (!strncmp(s+4,"604",3))
+ cpu = 604;
+ }
+}
+
+
+static char *strest(char *s,int n)
+/* returns ptr to the last n characters of string s */
+{
+ return (s + strlen(s) - n);
+}
+
+
+static int setlab(struct sinfo *p,char *lab)
+/* check for a valid local label */
+{
+ int i;
+
+ if (sscanf(lab,elf?".l%d":"l%d",&i) == 1) {
+ p->label = i;
+ return (1);
+ }
+ return (0);
+}
+
+
+static int lsreg(char *s)
+/* checks the operand for load/store addressing mode and returns */
+/* the base register on success, -1 otherwise */
+{
+ char *p = (s+strlen(s))-1;
+ int q;
+
+ while (p>s && *p!='(')
+ --p;
+ if (sscanf(p,elf?"(%d)":"(r%d)",&q) == 1)
+ return (q);
+ return (-1);
+}
+
+
+int sched_info(struct sinfo *p)
+{
+ char buf[16],oper[40],c;
+ int q1,q2,q3,z,i,x,n;
+
+ /* check for vscppc specific options in the source */
+ if (!strncmp(p->txt,"#vsc ",5)) {
+ sched_option(p->txt+5);
+ p->flags = BARRIER;
+ return (1);
+ }
+
+ if (!strncmp(p->txt,"#barrier",8)) {
+ /* an artificial barrier, used e.g. for inline-code */
+ p->flags = BARRIER;
+ return (1);
+ }
+
+ if (sscanf(p->txt," .%15s %39s",buf,oper) >= 1) {
+ /* assembler directive or macro */
+ p->flags = BARRIER;
+ return (1);
+ }
+
+ if (sscanf(p->txt,elf?".l%d:":"l%d:",&i) == 1) {
+ /* a local label */
+ p->label = i;
+ p->flags = LABEL;
+ return (1);
+ }
+
+ if (sscanf(p->txt," mffs%15s %39s",buf,oper) >= 1) {
+ /* mffs reads FPSCR and therefore has to be treated as a barrier, */
+ /* because FPSCR is never marked as used by the scheduler */
+ p->flags = BARRIER;
+ return (1);
+ }
+
+ if ((n = sscanf(p->txt," b%15s %39s",buf,oper)) >= 1) {
+ /* branch instruction */
+ p->latency = 1;
+ BSET(p->pipes,BPU);
+
+ if (n == 1) {
+ /* branch unconditional: b label */
+ if (setlab(p,buf)) {
+ p->flags = UNCOND_BRANCH;
+ return (1);
+ }
+ }
+ else {
+ char *a = strest(buf,3);
+
+ /* reject branch instructions ending with */
+ /* "lr", "ctr", "a" or "l", but accept "bnl" */
+ if ((strncmp(a+1,"lr",2) && strncmp(a,"ctr",3) &&
+ *(a+2)!='l' && *(a+2)!='a') ||
+ !strcmp(buf,"nl")) {
+
+ if (*buf == 'd') {
+ /* bdz... or bdnz... */
+ a = oper;
+ if (strcmp(buf,"dz") && strcmp(buf,"dnz")) {
+ while (*a && *a!=',')
+ a++;
+ if (*a == ',')
+ a++;
+ else
+ a = 0;
+ }
+ if (a) {
+ if (setlab(p,a)) {
+ p->flags = COND_BRANCH;
+ BSET(p->modifies,CTR);
+ /* @@@ unable to determine the used CCRs - set all to used */
+ for (x=CCR; x<(CCR+8); x++)
+ BSET(p->uses,x);
+ return (1);
+ }
+ }
+ }
+
+ else if (*buf == 'c') {
+ if (sscanf(oper,"%d,%d,%s",&q1,&q2,buf) == 3) {
+ /* conditional branch: bc m,n,label */
+ if (setlab(p,buf)) {
+ p->flags = COND_BRANCH;
+ BSET(p->uses,CCR+(q2>>2));
+ return (1);
+ }
+ }
+ }
+
+ else {
+ /* normal conditional branch: b<cond> [crN,]label */
+ a = buf;
+ if (sscanf(oper,elf?"%d,%s":"cr%d,%s",&i,buf) != 2) {
+ i = 0;
+ a = oper;
+ }
+ if (setlab(p,a)) {
+ p->flags = COND_BRANCH;
+ BSET(p->uses,CCR+i);
+ return (1);
+ }
+ }
+ }
+ }
+
+ p->flags = BARRIER;
+ return (1);
+ }
+
+
+ if (cpu == 603) {
+ /* scheduling for the PowerPC 603 */
+
+ if ((!elf && sscanf(p->txt," %15s %c%d,%39s",buf,&c,&z,oper) == 4) ||
+ (elf && sscanf(p->txt," %15s %d,%39s",buf,&z,oper) == 3)) {
+ if (elf) {
+ if ((buf[0]=='l' && buf[1]=='f') || (buf[0]=='s' && buf[2]=='f'))
+ c = 'f';
+ else
+ c = 'r';
+ }
+ if ((q1 = lsreg(oper))>=0 && (c=='r'||c=='f')) {
+ /* load/store instruction ...,d(rQ1) */
+
+ if (!strcmp(buf,"la")) {
+ /* la rZ,d(rQ1) is the same as: addi rZ,rQ1,d */
+ p->latency = 1;
+ BSET(p->pipes,IU);
+ BSET(p->pipes,SRU); /* addi may also execute in SRU */
+ BSET(p->uses,GPR+q1);
+ BSET(p->modifies,GPR+z);
+ return (1);
+ }
+
+ BSET(p->pipes,LSU);
+ if (*(strest(buf,1)) == 'u') /* update instruction? */
+ BSET(p->modifies,GPR+q1);
+ else
+ BSET(p->uses,GPR+q1);
+
+ if (c == 'r') {
+ /* integer load/store */
+
+ if (!strncmp(strest(buf,2),"mw",2)) {
+ /* load/store multiple word rz,i(rq1) */
+
+ if (*buf == 'l') {
+ p->latency = 2+(32-z);
+ for (x=z; x<32; x++)
+ BSET(p->modifies,GPR+x);
+ BSET(p->uses,MEM);
+ }
+ else {
+ p->latency = 1+(32-z);
+ for (x=z; x<32; x++)
+ BSET(p->uses,GPR+x);
+ BSET(p->modifies,MEM);
+ }
+ }
+ else {
+ /* load/store integer rz,i(rq1) */
+
+ p->latency = 3;
+ if(*buf == 'l') {
+ BSET(p->modifies,GPR+z);
+ BSET(p->uses,MEM);
+ }
+ else{
+ BSET(p->uses,GPR+z);
+ BSET(p->modifies,MEM);
+ }
+ }
+ }
+
+ else {
+ /* load/store float fz,d(rQ1) */
+
+ p->latency = 3;
+ if(*buf == 'l') {
+ BSET(p->modifies,FPR+z);
+ BSET(p->uses,MEM);
+ }
+ else{
+ BSET(p->uses,FPR+z);
+ BSET(p->modifies,MEM);
+ }
+ }
+
+ return (1);
+ }
+ }
+
+ if ((!elf && sscanf(p->txt," %15s %c%d,r%d,r%d",buf,&c,&z,&q1,&q2) == 5) ||
+ (elf && sscanf(p->txt," %15s %d,%d,%d",buf,&z,&q1,&q2) == 4)) {
+ if (*buf=='l' || (buf[0]=='s' && buf[1]=='t')) {
+ if (elf) {
+ if ((buf[0]=='l' && buf[1]=='f') || (buf[0]=='s' && buf[2]=='f'))
+ c = 'f';
+ else
+ c = 'r';
+ }
+
+ BSET(p->pipes,LSU);
+ BSET(p->uses,GPR+q2);
+ if (!strncmp(strest(buf,2),"ux",2)) /* update instruction? */
+ BSET(p->modifies,GPR+q1);
+ else
+ BSET(p->uses,GPR+q1);
+
+ if (c == 'r') {
+ /* integer load/store */
+
+ if (!strncmp(buf,"lsw",3) || !strncmp(buf,"stsw",4)) {
+ /* load/store string word rz,rq1,rq2/imm */
+ p->flags = BARRIER; /* too complex... ;) */
+ return (1);
+ }
+ else {
+ /* load/store integer indexed rz,rq1,rq2 */
+
+ p->latency = 3;
+ if(*buf == 'l') {
+ BSET(p->modifies,GPR+z);
+ BSET(p->uses,MEM);
+ }
+ else{
+ if (!strcmp(buf,"stwcx."))
+ p->latency = 8;
+ BSET(p->uses,GPR+z);
+ BSET(p->modifies,MEM);
+ }
+ return (1);
+ }
+ }
+
+ else if (c == 'f') {
+ /* load/store float indexed fz,rq1,rq2 */
+ p->latency = 3;
+ if(*buf == 'l') {
+ BSET(p->modifies,FPR+z);
+ BSET(p->uses,MEM);
+ }
+ else{
+ BSET(p->uses,FPR+z);
+ BSET(p->modifies,MEM);
+ }
+ return (1);
+ }
+ }
+ }
+
+ if (sscanf(p->txt,elf ? " fcm%15s %d,%d,%d" : " fcm%15s cr%d,f%d,f%d",
+ buf,&z,&q1,&q2) == 4) {
+ /* floating point compare CR0 */
+ p->latency = 3;
+ BSET(p->pipes,FPU);
+ BSET(p->modifies,CCR+z);
+ /*BSET(p->modifies,FPSCR);*/
+ BSET(p->uses,FPR+q1);
+ BSET(p->uses,FPR+q2);
+ return (1);
+ }
+ if (sscanf(p->txt,elf ? " fcm%15s %d,%d" : " fcm%15s f%d,f%d",
+ buf,&q1,&q2) == 3) {
+ /* floating point compare */
+ p->latency = 3;
+ BSET(p->pipes,FPU);
+ BSET(p->modifies,CCR);
+ /*BSET(p->modifies,FPSCR);*/
+ BSET(p->uses,FPR+q1);
+ BSET(p->uses,FPR+q2);
+ return (1);
+ }
+
+ if ((n = sscanf(p->txt,elf ? " f%15s %d,%d,%d,%d" :
+ " f%15s f%d,f%d,f%d,f%d",buf,&z,&q1,&q2,&q3))>=3) {
+ /* floating point operation with 2, 3 or 4 operands */
+
+#if 0
+ if (strncmp(buf,"abs",3) &&
+ strncmp(buf,"mr",2) &&
+ strncmp(buf,"nabs",4) &&
+ strncmp(buf,"neg",3) &&
+ strncmp(buf,"sel",3))
+ BSET(p->modifies,FPSCR); /* only some instr. don't alter FPSCR */
+#endif
+
+ if (!strncmp(buf,"divs",4) ||
+ !strncmp(buf,"res",3))
+ p->latency = 18;
+ else if (!strncmp(buf,"div",3))
+ p->latency = 33;
+ else if (!strncmp(buf,"mul",3) ||
+ !strncmp(buf,"madd",4) ||
+ !strncmp(buf,"msub",4) ||
+ !strncmp(buf,"nmadd",5) ||
+ !strncmp(buf,"nmsub",5))
+ p->latency = 4;
+ else
+ p->latency = 3;
+
+ if (*(strest(buf,1)) == '.')
+ BSET(p->modifies,CCR+1);
+ BSET(p->pipes,FPU);
+ BSET(p->uses,FPR+q1);
+ if (n >= 4) {
+ BSET(p->uses,FPR+q2);
+ if (n == 5)
+ BSET(p->uses,FPR+q3);
+ }
+ BSET(p->modifies,FPR+z);
+ return (1);
+ }
+
+ if (sscanf(p->txt,elf ? " cm%15s %d,%d,%d" : " cm%15s cr%d,r%d,r%d",
+ buf,&z,&q1,&q2) == 4) {
+ /* integer compare instruction */
+ p->latency = 1;
+ BSET(p->pipes,IU);
+ BSET(p->pipes,SRU);
+ BSET(p->modifies,CCR+z);
+ BSET(p->uses,GPR+q1);
+ if (*(strest(buf,1)) != 'i')
+ BSET(p->uses,GPR+q2);
+ return (1);
+ }
+ if (sscanf(p->txt,elf ? " cm%15s %d,%d" : " cm%15s r%d,r%d",
+ buf,&q1,&q2) == 3) {
+ /* integer compare instruction CR0 */
+ p->latency = 1;
+ BSET(p->pipes,IU);
+ BSET(p->pipes,SRU);
+ BSET(p->modifies,CCR);
+ BSET(p->uses,GPR+q1);
+ if (*(strest(buf,1)) != 'i')
+ BSET(p->uses,GPR+q2);
+ return (1);
+ }
+
+ if (!elf) {
+ if (sscanf(p->txt," cm%15s cr%d,r%d,%d",buf,&z,&q1,&i) == 4) {
+ /* immediate integer compare instruction */
+ p->latency = 1;
+ BSET(p->pipes,IU);
+ BSET(p->pipes,SRU);
+ BSET(p->modifies,CCR+z);
+ BSET(p->uses,GPR+q1);
+ return (1);
+ }
+ if (sscanf(p->txt," cm%15s r%d,%d",buf,&q1,&i) == 3) {
+ /* immediate integer compare instruction CR0 */
+ p->latency = 1;
+ BSET(p->pipes,IU);
+ BSET(p->pipes,SRU);
+ BSET(p->modifies,CCR+z);
+ BSET(p->uses,GPR+q1);
+ return (1);
+ }
+ }
+
+ if ((n = sscanf(p->txt," cr%15s %d,%d,%d",buf,&z,&q1,&q2)) >= 2) {
+ /* condition code register operation (vbcc uses this version) */
+ p->latency = 1;
+ BSET(p->pipes,SRU);
+ BSET(p->modifies,CCR+(z>>4));
+ if (n >= 3) {
+ BSET(p->uses,CCR+(q1>>4));
+ if (n == 4)
+ BSET(p->uses,CCR+(q2>>4));
+ }
+ return (1);
+ }
+
+ if (sscanf(p->txt,elf ? " rlw%15s %d,%d,%d,%d,%d" :
+ " rlw%15s r%d,r%d,%d,%d,%d",buf,&z,&q1,&i,&n,&x) == 6) {
+ /* rotate left: rlwimi, rlwinm, rlwnm r1,r2,x,y,z */
+ p->latency = 1;
+ BSET(p->pipes,IU);
+ if (*(strest(buf,1)) == '.')
+ BSET(p->modifies,CCR);
+ BSET(p->uses,GPR+q1);
+ BSET(p->modifies,GPR+z);
+ return (1);
+ }
+
+ if (sscanf(p->txt,elf ? " %15s %d,%d,%c" : " %15s r%d,r%d,%c",
+ buf,&z,&q1,&c) == 4) {
+ /* op r1,r2,imm */
+ if (!strncmp(buf,"addi",4) ||
+ !strncmp(buf,"andi",4) ||
+ !strncmp(buf,"mulli",5) ||
+ !strncmp(buf,"ori",3) ||
+ !strncmp(buf,"slwi",4) ||
+ !strncmp(buf,"srwi",4) ||
+ !strncmp(buf,"srawi",5) ||
+ !strncmp(buf,"subi",4) ||
+ !strncmp(buf,"xori",4)) {
+ char *a = strest(buf,1);
+
+ if (*buf == 'm') /* mulli */
+ p->latency = 3;
+ else
+ p->latency = 1;
+ BSET(p->pipes,IU);
+ if (!strncmp(buf,"add",3) && *(buf+4)!='c')
+ BSET(p->pipes,SRU); /* addi/addis may also execute in SRU */
+ if (*a == '.') {
+ BSET(p->modifies,CCR);
+ --a;
+ }
+ if (*a == 'c')
+ BSET(p->modifies,XER);
+ BSET(p->uses,GPR+q1);
+ BSET(p->modifies,GPR+z);
+ return (1);
+ }
+ }
+
+ if (sscanf(p->txt,elf ? " %15s %d,0,%d" : " %15s r%d,0,r%d",
+ buf,&z,&q2) == 3) {
+ /* op r1,0,r3 */
+ if (!strncmp(buf,"add",3) ||
+ !strncmp(buf,"sub",3)) {
+ p->latency = 1;
+ BSET(p->pipes,IU);
+ if (*(strest(buf,1)) == '.')
+ BSET(p->modifies,CCR);
+ else
+ BSET(p->pipes,SRU); /* add/addo may also execute in SRU */
+ BSET(p->uses,GPR+q2);
+ BSET(p->modifies,GPR+z);
+ return (1);
+ }
+ }
+
+ if (sscanf(p->txt,elf ? " %15s %d,%d,%d" : " %15s r%d,r%d,r%d",
+ buf,&z,&q1,&q2) == 4) {
+ /* op r1,r2,r3 */
+ if (!strncmp(buf,"add",3) ||
+ !strncmp(buf,"and",3) ||
+ !strncmp(buf,"div",3) ||
+ !strncmp(buf,"eqv",3) ||
+ !strncmp(buf,"mul",3) ||
+ !strncmp(buf,"nand",4) ||
+ !strncmp(buf,"nor",3) ||
+ !strncmp(buf,"or",2) ||
+ !strncmp(buf,"sl",2) ||
+ !strncmp(buf,"sr",2) ||
+ !strncmp(buf,"sub",3) ||
+ !strncmp(buf,"xor",3)) {
+ char *a = strest(buf,1);
+
+ if (!strncmp(buf,"mul",3)) {
+ if (*(buf+5) == 'u')
+ p->latency = 6; /* mulhwu needs 6 cycles */
+ else
+ p->latency = 5;
+ if (*(buf+3) == 'l')
+ BSET(p->modifies,XER);
+ }
+ else if (!strncmp(buf,"div",3)) {
+/* p->latency = 37;*/
+ p->latency = 20; /* 603e has 20 since PID7 */
+ BSET(p->modifies,XER);
+ }
+ else
+ p->latency = 1;
+ BSET(p->pipes,IU);
+ if (!strcmp(buf,"add") || !strcmp(buf,"addo"))
+ BSET(p->pipes,SRU); /* add/addo may also execute in SRU */
+
+ if (*a == '.') {
+ BSET(p->modifies,CCR);
+ --a;
+ }
+ if (*a == 'o') {
+ BSET(p->modifies,XER);
+ --a;
+ }
+ if (*a == 'c') {
+ BSET(p->modifies,XER);
+ --a;
+ }
+ if (*a == 'e')
+ BSET(p->uses,XER);
+ BSET(p->uses,GPR+q1);
+ BSET(p->uses,GPR+q2);
+ BSET(p->modifies,GPR+z);
+ return (1);
+ }
+ }
+
+ if (sscanf(p->txt,elf ? " l%15s %d,%c" : " l%15s r%d,%c",
+ buf,&z,&c) == 3) {
+ if (*buf == 'i') {
+ /* li, lis -> addi, addis */
+ p->latency = 1;
+ BSET(p->pipes,IU);
+ BSET(p->pipes,SRU);
+ BSET(p->modifies,GPR+z);
+ return (1);
+ }
+ }
+
+ if (sscanf(p->txt,elf ? " %15s %d,%d" : " %15s r%d,r%d",
+ buf,&z,&q1) == 3) {
+ /* op r1,r2 */
+ if (!strncmp(buf,"add",3) ||
+ !strncmp(buf,"exts",4) ||
+ !strncmp(buf,"mr",2) ||
+ !strncmp(buf,"neg",3) ||
+ !strncmp(buf,"sub",3)) {
+ char *a = strest(buf,1);
+
+ p->latency = 1;
+ if (*buf=='a' || *buf=='s')
+ BSET(p->uses,XER); /* addme/addze/subfme/subfze/... */
+ BSET(p->pipes,IU);
+ if (*a == '.') {
+ BSET(p->modifies,CCR);
+ --a;
+ }
+ if (*a == 'o') {
+ BSET(p->modifies,XER);
+ }
+ BSET(p->uses,GPR+q1);
+ BSET(p->modifies,GPR+z);
+ return (1);
+ }
+ }
+
+ if (sscanf(p->txt,elf?" m%15s %d":" m%15s r%d",buf,&z) == 2) {
+ /* mtxxx, mfxxx: move from/to special registers */
+ int reg=0;
+
+ if (!strcmp(&buf[1],"xer"))
+ reg = XER;
+ else if (!strcmp(&buf[1],"ctr"))
+ reg = CTR;
+ else if (!strcmp(&buf[1],"lr"))
+ reg = LR;
+ else if (!strncmp(&buf[1],"fs",2))
+ reg = FPSCR;
+ if (reg) {
+ if (reg == FPSCR) {
+ p->latency = 3;
+ BSET(p->pipes,FPU);
+ /*if (*buf == 'f') {
+ BSET(p->uses,reg);
+ BSET(p->modifies,z);
+ }
+ else {*/
+ BSET(p->uses,z);
+ BSET(p->modifies,reg);
+ /*}*/
+ }
+ else {
+ BSET(p->pipes,SRU);
+ if (*buf == 'f') {
+ p->latency = 1;
+ BSET(p->uses,reg);
+ BSET(p->modifies,z);
+ }
+ else {
+ p->latency = 2;
+ BSET(p->uses,z);
+ BSET(p->modifies,reg);
+ }
+ }
+ return (1);
+ }
+ }
+ }
+
+
+ else if (cpu == 604) {
+ /* scheduling for the PowerPC 604 */
+
+ if ((!elf && sscanf(p->txt," %15s %c%d,%39s",buf,&c,&z,oper) == 4) ||
+ (elf && sscanf(p->txt," %15s %d,%39s",buf,&z,oper) == 3)) {
+ if (elf) {
+ if ((buf[0]=='l' && buf[1]=='f') || (buf[0]=='s' && buf[2]=='f'))
+ c = 'f';
+ else
+ c = 'r';
+ }
+ if ((q1 = lsreg(oper))>=0 && (c=='r'||c=='f')) {
+ /* load/store instruction ...,d(rQ1) */
+
+ if (!strcmp(buf,"la")) {
+ /* la rZ,d(rQ1) is the same as: addi rZ,rQ1,d */
+ p->latency = 1;
+ BSET(p->pipes,SCIU1);
+ BSET(p->pipes,SCIU2);
+ BSET(p->uses,GPR+q1);
+ BSET(p->modifies,GPR+z);
+ return (1);
+ }
+
+ BSET(p->pipes,LSU);
+ if (*(strest(buf,1)) == 'u') /* update instruction? */
+ BSET(p->modifies,GPR+q1);
+ else
+ BSET(p->uses,GPR+q1);
+
+ if (c == 'r') {
+ /* integer load/store */
+
+ if (!strncmp(strest(buf,2),"mw",2)) {
+ /* load/store multiple word rz,i(rq1) */
+
+ p->latency = 2+(32-z);
+ if (*buf == 'l') {
+ for (x=z; x<32; x++)
+ BSET(p->modifies,GPR+x);
+ BSET(p->uses,MEM);
+ }
+ else {
+ for (x=z; x<32; x++)
+ BSET(p->uses,GPR+x);
+ BSET(p->modifies,MEM);
+ }
+ }
+ else {
+ /* load/store integer rz,i(rq1) */
+
+ if(*buf == 'l') {
+ p->latency = 2;
+ BSET(p->modifies,GPR+z);
+ BSET(p->uses,MEM);
+ }
+ else{
+ p->latency = 3;
+ BSET(p->uses,GPR+z);
+ BSET(p->modifies,MEM);
+ }
+ }
+ }
+
+ else {
+ /* load/store float fz,d(rQ1) */
+
+ p->latency = 3;
+ if(*buf == 'l') {
+ BSET(p->modifies,FPR+z);
+ BSET(p->uses,MEM);
+ }
+ else{
+ BSET(p->uses,FPR+z);
+ BSET(p->modifies,MEM);
+ }
+ }
+
+ return (1);
+ }
+ }
+
+ if ((!elf && sscanf(p->txt," %15s %c%d,r%d,r%d",buf,&c,&z,&q1,&q2) == 5) ||
+ (elf && sscanf(p->txt," %15s %d,%d,%d",buf,&z,&q1,&q2) == 4)) {
+ if (*buf=='l' || (buf[0]=='s' && buf[1]=='t')) {
+ if (elf) {
+ if ((buf[0]=='l' && buf[1]=='f') || (buf[0]=='s' && buf[2]=='f'))
+ c = 'f';
+ else
+ c = 'r';
+ }
+
+ BSET(p->pipes,LSU);
+ BSET(p->uses,GPR+q2);
+ if (!strncmp(strest(buf,2),"ux",2)) /* update instruction? */
+ BSET(p->modifies,GPR+q1);
+ else
+ BSET(p->uses,GPR+q1);
+
+ if (c == 'r') {
+ /* integer load/store */
+
+ if (!strncmp(buf,"lsw",3) || !strncmp(buf,"stsw",4)) {
+ /* load/store string word rz,rq1,rq2/imm */
+ p->flags = BARRIER; /* too complex... ;) */
+ return (1);
+ }
+ else {
+ /* load/store integer indexed rz,rq1,rq2 */
+
+ if(*buf == 'l') {
+ p->latency = 2;
+ BSET(p->modifies,GPR+z);
+ BSET(p->uses,MEM);
+ }
+ else{
+ p->latency = 3;
+ BSET(p->uses,GPR+z);
+ BSET(p->modifies,MEM);
+ }
+ return (1);
+ }
+ }
+
+ else if (c == 'f') {
+ /* load/store float indexed fz,rq1,rq2 */
+ p->latency = 3;
+ if(*buf == 'l') {
+ BSET(p->modifies,FPR+z);
+ BSET(p->uses,MEM);
+ }
+ else{
+ BSET(p->uses,FPR+z);
+ BSET(p->modifies,MEM);
+ }
+ return (1);
+ }
+ }
+ }
+
+ if (sscanf(p->txt,elf ? " fcm%15s %d,%d,%d" : " fcm%15s cr%d,f%d,f%d",
+ buf,&z,&q1,&q2) == 4) {
+ /* floating point compare CR0 */
+ p->latency = 3;
+ BSET(p->pipes,FPU);
+ BSET(p->modifies,CCR+z);
+ /*BSET(p->modifies,FPSCR);*/
+ BSET(p->uses,FPR+q1);
+ BSET(p->uses,FPR+q2);
+ return (1);
+ }
+ if (sscanf(p->txt,elf ? " fcm%15s %d,%d" : " fcm%15s f%d,f%d",
+ buf,&q1,&q2) == 3) {
+ /* floating point compare */
+ p->latency = 3;
+ BSET(p->pipes,FPU);
+ BSET(p->modifies,CCR);
+ /*BSET(p->modifies,FPSCR);*/
+ BSET(p->uses,FPR+q1);
+ BSET(p->uses,FPR+q2);
+ return (1);
+ }
+
+ if ((n = sscanf(p->txt,elf ? " f%15s %d,%d,%d,%d" :
+ " f%15s f%d,f%d,f%d,f%d",buf,&z,&q1,&q2,&q3))>=3) {
+ /* floating point operation with 2, 3 or 4 operands */
+
+#if 0
+ if (strncmp(buf,"abs",3) &&
+ strncmp(buf,"mr",2) &&
+ strncmp(buf,"nabs",4) &&
+ strncmp(buf,"neg",3) &&
+ strncmp(buf,"sel",3))
+ BSET(p->modifies,FPSCR); /* only some instr. don't alter FPSCR */
+#endif
+
+ if (!strncmp(buf,"divs",4) ||
+ !strncmp(buf,"res",3))
+ p->latency = 18;
+ else if (!strncmp(buf,"div",3))
+ p->latency = 32;
+ else
+ p->latency = 3;
+
+ if (*(strest(buf,1)) == '.')
+ BSET(p->modifies,CCR+1);
+ BSET(p->pipes,FPU);
+ BSET(p->uses,FPR+q1);
+ if (n >= 4) {
+ BSET(p->uses,FPR+q2);
+ if (n == 5)
+ BSET(p->uses,FPR+q3);
+ }
+ BSET(p->modifies,FPR+z);
+ return (1);
+ }
+
+ if (sscanf(p->txt,elf ? " cm%15s %d,%d,%d" : " cm%15s cr%d,r%d,r%d",
+ buf,&z,&q1,&q2) == 4) {
+ /* integer compare instruction */
+ p->latency = 1;
+ BSET(p->pipes,SCIU1);
+ BSET(p->pipes,SCIU2);
+ BSET(p->modifies,CCR+z);
+ BSET(p->uses,GPR+q1);
+ if (*(strest(buf,1)) != 'i')
+ BSET(p->uses,GPR+q2);
+ return (1);
+ }
+ if (sscanf(p->txt,elf ? " cm%15s %d,%d" : " cm%15s r%d,r%d",
+ buf,&q1,&q2) == 3) {
+ /* integer compare instruction CR0 */
+ p->latency = 1;
+ BSET(p->pipes,SCIU1);
+ BSET(p->pipes,SCIU2);
+ BSET(p->modifies,CCR);
+ BSET(p->uses,GPR+q1);
+ if (*(strest(buf,1)) != 'i')
+ BSET(p->uses,GPR+q2);
+ return (1);
+ }
+
+ if (!elf) {
+ if (sscanf(p->txt," cm%15s cr%d,r%d,%d",buf,&z,&q1,&i) == 4) {
+ /* immediate integer compare instruction */
+ p->latency = 1;
+ BSET(p->pipes,SCIU1);
+ BSET(p->pipes,SCIU2);
+ BSET(p->modifies,CCR+z);
+ BSET(p->uses,GPR+q1);
+ return (1);
+ }
+ if (sscanf(p->txt," cm%15s r%d,%d",buf,&q1,&i) == 3) {
+ /* immediate integer compare instruction CR0 */
+ p->latency = 1;
+ BSET(p->pipes,SCIU1);
+ BSET(p->pipes,SCIU2);
+ BSET(p->modifies,CCR+z);
+ BSET(p->uses,GPR+q1);
+
+ return (1);
+ }
+ }
+
+ if ((n = sscanf(p->txt," cr%15s %d,%d,%d",buf,&z,&q1,&q2)) >= 2) {
+ /* condition code register operation (vbcc uses this version) */
+ p->latency = 1;
+ BSET(p->pipes,CRU);
+ BSET(p->modifies,CCR+(z>>4));
+ if (n >= 3) {
+ BSET(p->uses,CCR+(q1>>4));
+ if (n == 4)
+ BSET(p->uses,CCR+(q2>>4));
+ }
+ return (1);
+ }
+
+ if (sscanf(p->txt,elf ? " rlw%15s %d,%d,%d,%d,%d" :
+ " rlw%15s r%d,r%d,%d,%d,%d",buf,&z,&q1,&i,&n,&x) == 6) {
+ /* rotate left: rlwimi, rlwinm, rlwnm r1,r2,x,y,z */
+ p->latency = 1;
+ BSET(p->pipes,SCIU1);
+ BSET(p->pipes,SCIU2);
+ if (*(strest(buf,1)) == '.')
+ BSET(p->modifies,CCR);
+ BSET(p->uses,GPR+q1);
+ BSET(p->modifies,GPR+z);
+ return (1);
+ }
+
+ if (sscanf(p->txt,elf ? " %15s %d,%d,%c" : " %15s r%d,r%d,%c",
+ buf,&z,&q1,&c) == 4) {
+ /* op r1,r2,imm */
+ if (!strncmp(buf,"addi",4) ||
+ !strncmp(buf,"andi",4) ||
+ !strncmp(buf,"mulli",5) ||
+ !strncmp(buf,"ori",3) ||
+ !strncmp(buf,"slwi",4) ||
+ !strncmp(buf,"srwi",4) ||
+ !strncmp(buf,"srawi",5) ||
+ !strncmp(buf,"subi",4) ||
+ !strncmp(buf,"xori",4)) {
+ char *a = strest(buf,1);
+
+ if (*buf == 'm') { /* mulli */
+ p->latency = 3;
+ BSET(p->pipes,MCIU);
+ }
+ else {
+ p->latency = 1;
+ BSET(p->pipes,SCIU1);
+ BSET(p->pipes,SCIU2);
+ }
+ if (*a == '.') {
+ BSET(p->modifies,CCR);
+ --a;
+ }
+ if (*a == 'c')
+ BSET(p->modifies,XER);
+ BSET(p->uses,GPR+q1);
+ BSET(p->modifies,GPR+z);
+ return (1);
+ }
+ }
+
+ if (sscanf(p->txt,elf ? " %15s %d,0,%d" : " %15s r%d,0,r%d",
+ buf,&z,&q2) == 3) {
+ /* op r1,0,r3 */
+ if (!strncmp(buf,"add",3) ||
+ !strncmp(buf,"sub",3)) {
+ p->latency = 1;
+ BSET(p->pipes,SCIU1);
+ BSET(p->pipes,SCIU2);
+ if (*(strest(buf,1)) == '.')
+ BSET(p->modifies,CCR);
+ else
+ BSET(p->pipes,SRU); /* add/addo may also execute in SRU */
+ BSET(p->uses,GPR+q2);
+ BSET(p->modifies,GPR+z);
+ return (1);
+ }
+ }
+
+ if (sscanf(p->txt,elf ? " %15s %d,%d,%d" : " %15s r%d,r%d,r%d",
+ buf,&z,&q1,&q2) == 4) {
+ /* op r1,r2,r3 */
+ if (!strncmp(buf,"add",3) ||
+ !strncmp(buf,"and",3) ||
+ !strncmp(buf,"div",3) ||
+ !strncmp(buf,"eqv",3) ||
+ !strncmp(buf,"mul",3) ||
+ !strncmp(buf,"nand",4) ||
+ !strncmp(buf,"nor",3) ||
+ !strncmp(buf,"or",2) ||
+ !strncmp(buf,"sl",2) ||
+ !strncmp(buf,"sr",2) ||
+ !strncmp(buf,"sub",3) ||
+ !strncmp(buf,"xor",3)) {
+ char *a = strest(buf,1);
+
+ if (!strncmp(buf,"mul",3)) {
+ p->latency = 4;
+ BSET(p->pipes,MCIU);
+ if (*(buf+3) == 'l')
+ BSET(p->modifies,XER);
+ }
+ else if (!strncmp(buf,"div",3)) {
+ p->latency = 20;
+ BSET(p->pipes,MCIU);
+ BSET(p->modifies,XER);
+ }
+ else {
+ p->latency = 1;
+ BSET(p->pipes,SCIU1);
+ BSET(p->pipes,SCIU2);
+ }
+ if (*a == '.') {
+ BSET(p->modifies,CCR);
+ --a;
+ }
+ if (*a == 'o') {
+ BSET(p->modifies,XER);
+ --a;
+ }
+ if (*a == 'c') {
+ BSET(p->modifies,XER);
+ --a;
+ }
+ if (*a == 'e')
+ BSET(p->uses,XER);
+ BSET(p->uses,GPR+q1);
+ BSET(p->uses,GPR+q2);
+ BSET(p->modifies,GPR+z);
+ return (1);
+ }
+ }
+
+ if (sscanf(p->txt,elf ? " l%15s %d,%c" : " l%15s r%d,%c",
+ buf,&z,&c) == 3) {
+ if (*buf == 'i') {
+ /* li, lis -> addi, addis */
+ p->latency = 1;
+ BSET(p->pipes,SCIU1);
+ BSET(p->pipes,SCIU2);
+ BSET(p->modifies,GPR+z);
+ return (1);
+ }
+ }
+
+ if (sscanf(p->txt,elf ? " %15s %d,%d" : " %15s r%d,r%d",
+ buf,&z,&q1) == 3) {
+ /* op r1,r2 */
+ if (!strncmp(buf,"add",3) ||
+ !strncmp(buf,"exts",4) ||
+ !strncmp(buf,"mr",2) ||
+ !strncmp(buf,"neg",3) ||
+ !strncmp(buf,"sub",3)) {
+ char *a = strest(buf,1);
+
+ p->latency = 1;
+ BSET(p->pipes,SCIU1);
+ BSET(p->pipes,SCIU2);
+ if (*buf=='a' || *buf=='s')
+ BSET(p->uses,XER); /* addme/addze/subfme/subfze/... */
+ if (*a == '.') {
+ BSET(p->modifies,CCR);
+ --a;
+ }
+ if (*a == 'o') {
+ BSET(p->modifies,XER);
+ }
+ BSET(p->uses,GPR+q1);
+ BSET(p->modifies,GPR+z);
+ return (1);
+ }
+ }
+
+ if (sscanf(p->txt,elf?" m%15s %d":" m%15s r%d",buf,&z) == 2) {
+ /* mtxxx, mfxxx: move from/to special registers */
+ int reg=0;
+
+ if (!strcmp(&buf[1],"xer"))
+ reg = XER;
+ else if (!strcmp(&buf[1],"ctr"))
+ reg = CTR;
+ else if (!strcmp(&buf[1],"lr"))
+ reg = LR;
+ else if (!strncmp(&buf[1],"fs",2))
+ reg = FPSCR;
+ if (reg) {
+ if (reg == FPSCR) {
+ p->latency = 3;
+ BSET(p->pipes,FPU);
+ /*if (*buf == 'f') {
+ BSET(p->uses,reg);
+ BSET(p->modifies,z);
+ }
+ else {*/
+ BSET(p->uses,z);
+ BSET(p->modifies,reg);
+ /*}*/
+ }
+ else {
+ BSET(p->pipes,MCIU);
+ if (*buf == 'f') {
+ p->latency = 3;
+ BSET(p->uses,reg);
+ BSET(p->modifies,z);
+ }
+ else {
+ p->latency = 1;
+ BSET(p->uses,z);
+ BSET(p->modifies,reg);
+ }
+ }
+ return (1);
+ }
+ }
+ }
+
+ p->flags = BARRIER;
+ return (1);
+}
diff --git a/machines/ppc/schedule.h b/machines/ppc/schedule.h
new file mode 100755
index 0000000..9d6fba8
--- /dev/null
+++ b/machines/ppc/schedule.h
@@ -0,0 +1,53 @@
+/*
+ * vscppc
+ *
+ * vbcc PowerPC scheduler
+ * (C)1998 by Frank Wille <frank@phoenix.owl.de>
+ *
+ * vscppc is freeware and part of the portable and retargetable ANSI C
+ * compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
+ * vscppc may be freely redistributed as long as no modifications are
+ * made and nothing is charged for it. Non-commercial usage is allowed
+ * without any restrictions.
+ * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
+ * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
+ *
+ * History:
+ * V0.3 20-Jul-98
+ * Differentiation between 603 and 604. Now, scheduling takes
+ * place with regard to the real PowerPC architecture.
+ * V0.1 10-Jul-98
+ * vscppc seems to be stable enough, after some tests.
+ * However, it still needs a lot of fine tuning.
+ * A differentiation between the PPC CPUs (603e, 604e) is missing.
+ * V0.0 09-Jul-98
+ * File created.
+ *
+ */
+
+#define PIPES 7 /* the max. number of pipes, as required by the 604 */
+
+/* Pipe Names 603 */
+#define BPU 0 /* Branch Prediction Unit */
+#define SRU 1 /* Special Reg. Unit */
+#define IU 2 /* Integer Unit */
+#define FPU 5 /* Floating Point Unit */
+#define LSU 6 /* Load Store Unit */
+
+/* Pipe Names 604 */
+#define CRU 1 /* Condition Register Unit */
+#define SCIU1 2 /* Single Cycle Integer Unit #1 */
+#define SCIU2 3 /* Single Cycle Integer Unit #2 */
+#define MCIU 4 /* Multiple Cycle Integer Unit */
+
+
+#define REGS 76 /* 32 GPR, 32 FPR, 8 CCR, LR, CTR, XER, FPSCR */
+
+/* REG-offsets */
+#define GPR 0
+#define FPR 32
+#define CCR 64
+#define XER 72
+#define CTR 73
+#define LR 74
+#define FPSCR 75
diff --git a/machines/qnice/machine.c b/machines/qnice/machine.c
new file mode 100755
index 0000000..b919925
--- /dev/null
+++ b/machines/qnice/machine.c
@@ -0,0 +1,2412 @@
+/* Code generator for qnice cpu. */
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for qnice V0.1 (c) in 2016 by Volker Barthelmann";
+
+/* Commandline-flags the code-generator accepts */
+int g_flags[MAXGF]={VALFLAG,0,0,0,
+ 0,0,0,0,
+ 0,VALFLAG};
+char *g_flags_name[MAXGF]={"cpu","int32","no-delayed-popping","const-in-data",
+ "merge-constants","no-peephole","mtiny","mlarge",
+ "mhuge","rw-threshold","soft-mul"};
+union ppi g_flags_val[MAXGF];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","bit","char","short","int","long","long long",
+ "float","double","long double","void",
+ "near-pointer","far-pointer","huge-pointer",
+ "array","struct","union","enum","function"};
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT of the target machine. */
+zmax char_bit;
+
+/* Sizes of all elementary types in bytes. */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. */
+char *regnames[]={"noreg","R0","R1","R2","R3","R4","R5","R6","R7",
+ "R8","R9","R10","R11","R12","R13","R14","R15",
+ "R0/R1","R2/R3","R4/R5","R6/R7",
+ "R8/R9","R11/R12"};
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* Type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1]={0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,1,1};
+
+int reg_prio[MAXR+1]={0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1};
+
+struct reg_handle empty_reg_handle={0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__interrupt","__rbank","__norbank",0};
+#define INTERRUPT 1
+#define RBANK 2
+#define NORBANK 4
+
+
+/****************************************/
+/* Some private data and functions. */
+/****************************************/
+
+static long malign[MAX_TYPE+1]= {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+static long msizetab[MAX_TYPE+1]={0,1,1,1,1,2,4,2,4,4,0,1,2,2,0,0,0,1,0,1,1};
+
+struct Typ ityp={SHORT},ltyp={LONG};
+
+#define INT32 (g_flags[1]&USEDFLAG)
+#define NOPEEP (g_flags[5]&USEDFLAG)
+#define TINY 1 /*(g_flags[6]&USEDFLAG)*/
+#define LARGE 0 /*(g_flags[7]&USEDFLAG)*/
+#define HUGE 0 /*(g_flags[8]&USEDFLAG)*/
+#define SOFTMUL (g_flags[10]&USEDFLAG)
+
+
+#define NDATA 0
+#define NBSS 1
+#define NCDATA 2
+#define FDATA 3
+#define FBSS 4
+#define FCDATA 5
+#define HDATA 6
+#define HBSS 7
+#define HCDATA 8
+#define CODE 9
+#define SPECIAL 10
+#define BITS 11
+
+static int section=-1,newobj,scnt;
+static char *codename="\t.text\n",
+ *ndataname="\t.data\n",
+ *fdataname="\t.data\n",
+ *hdataname="\t.data\n",
+ *nbssname="\t.bss\n",
+ *fbssname="\t.bss\n",
+ *hbssname="\t.bss\n",
+ *ncdataname="\t.text\n",
+ *fcdataname="\t.text\n",
+ *hcdataname="\t.text\n";
+
+#define POST_INC 1
+#define PRE_DEC 2
+
+extern int static_cse, dref_cse;
+
+/* (user)stack-pointer, pointer-tmp, int-tmp; reserved for compiler */
+static const int sp=14,sr=15,pc=16,t1=12,t2=13,MTMP1=22;
+static const int r8=9,r9=10,r8r9=21;
+static int tmp1,tmp2,tmp3,tmp4,t2_used;
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+static int scratchreg(int,struct IC *);
+static struct Var nvar,fvar;
+static int load_const;
+static struct IC *icp;
+
+static char *marray[]={0,
+ "__far=__attr(\"far\")",
+ "__near=__attr(\"near\")",
+ "__huge=__attr(\"huge\")",
+ "__section(x,y)=__vattr(\"section(\"#x\",\"#y\")\")",
+ "__interrupt(x)=__interrupt __vattr(\"ivec(\"__str(x)\")\")",
+ "__QNICE__",
+ "__SIZE_T_INT=1",
+ "__str(x)=#x",
+ 0};
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static long loff,stack,stackoffset,notpopped,dontpop,maxpushed;
+
+static char *ccs[]={"z","!z","v","!v","??","??"};
+static char *ccu[]={"z","!z","n","!n","??","??"};
+
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"shl","shr","add","sub"};
+
+static char *dct[]={"",".bit",".short",".short",".short",".short",".short",".short",".short",".short",
+ "(void)",".short",".long",".long"};
+static int pushedsize,pushorder=2;
+static char *idprefix="_",*labprefix="l";
+static int exit_label,have_frame,stackchecklabel,stack_valid;
+static char *ret,*call,*jump;
+static int frame_used;
+static int rwthreshold;
+
+#define STR_NEAR "near"
+#define STR_FAR "far"
+#define STR_HUGE "huge"
+
+#define ISNULL() (zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
+#define ISLWORD(t) ((t&NQ)==LONG||(t&NQ)==FPOINTER||(t&NQ)==HPOINTER||(t&NQ)==FLOAT)
+#define ISHWORD(t) ((t&NQ)==INT||(t&NQ)==SHORT||(t&NQ)==CHAR||(t&NQ)==NPOINTER)
+#define ISSTATIC(v) ((v)->storage_class==EXTERN||(v)->storage_class==STATIC)
+
+static int ISFAR(struct Var *v)
+{
+ struct Typ *vt;
+ if(v==&nvar) return 0;
+ if(v==&fvar) return 1;
+ vt=v->vtyp;
+ while(ISARRAY(vt->flags)) vt=vt->next;
+ if(vt->attr&&strstr(STR_NEAR,vt->attr))
+ return 0;
+ if(HUGE||LARGE)
+ return 1;
+ if(vt->attr&&(strstr(STR_FAR,vt->attr)||strstr(STR_HUGE,vt->attr)))
+ return 1;
+ return 0;
+}
+
+static int special_section(FILE *f,struct Var *v)
+{
+ char *sec,*e;
+ if(!v->vattr) return 0;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return 0;
+ sec+=strlen("section(");
+ emit(f,"\t.section\t");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+static struct fpconstlist {
+ struct fpconstlist *next;
+ int label,typ;
+ union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+ struct fpconstlist *p=firstfpc;
+ t&=NQ;
+ if(g_flags[4]&USEDFLAG){
+ for(p=firstfpc;p;p=p->next){
+ if(t==p->typ){
+ eval_const(&p->val,t);
+ if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+ if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+ if(t==LDOUBLE&&zldeqto(vldouble,o->val.vldouble)) return p->label;
+ }
+ }
+ }
+ p=mymalloc(sizeof(struct fpconstlist));
+ p->next=firstfpc;
+ p->label=++label;
+ p->typ=t;
+ p->val=o->val;
+ firstfpc=p;
+ return p->label;
+}
+static void callee_push(long push)
+{
+ if(push-stackoffset>stack)
+ stack=push-stackoffset;
+}
+static void push(long push)
+{
+ stackoffset-=push;
+ if(stackoffset<maxpushed)
+ maxpushed=stackoffset;
+ if(-maxpushed>stack) stack=-maxpushed;
+}
+static void pop(long pop)
+{
+ stackoffset+=pop;
+}
+int pointer_type(struct Typ *p)
+{
+ struct Typ *merk=p;
+ if(!p) ierror(0);
+ while(ISARRAY(p->flags)||ISFUNC(p->flags)) p=p->next;
+ if(p->attr){
+ if(strstr(p->attr,STR_HUGE)) return HPOINTER;
+ if(strstr(p->attr,STR_FAR)) return FPOINTER;
+ if(strstr(p->attr,STR_NEAR)) return NPOINTER;
+ }
+ if((merk->flags&NQ)==FUNKT){
+ if(TINY)
+ return NPOINTER;
+ else
+ return HPOINTER;
+ }
+ if(LARGE)
+ return FPOINTER;
+ else if(HUGE)
+ return HPOINTER;
+ else
+ return NPOINTER;
+}
+
+/* return non-zero if IC is implemented by a function call */
+static int islibcall(struct IC *p)
+{
+ /* TODO: check if necessary */
+ return 0;
+}
+
+static long voff(struct obj *p)
+{
+ if(p->v->offset<0)
+ return loff-zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset+pushedsize;
+ return zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset;
+}
+static int alignment(struct obj *o)
+{
+ if(o->flags&DREFOBJ) return 1;
+ if(!(o->flags&VAR)) ierror(0);
+ if(ISSTATIC(o->v)) return zm2l(o->val.vmax)&1;
+ return voff(o)&1;
+}
+
+static void emit_obj(FILE *f,struct obj *p,int t)
+/* output an operand */
+{
+ if(p->am){
+ if(p->am->flags==POST_INC){
+ emit(f,"@%s++",regnames[p->am->base]);
+ return;
+ }else if(p->am->flags==PRE_DEC){
+ emit(f,"@--%s",regnames[p->am->base]);
+ return;
+ }else{
+ ierror(0);
+ }
+ }
+ if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,"@");
+ /*if(p->flags&VARADR) ierror(0);*/
+ if((p->flags&(VAR|REG))==VAR){
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+ if(voff(p))
+ emit(f,"@%s+#%ld",regnames[sp],voff(p));
+ else emit(f,"@%s",regnames[sp]);
+ }else{
+ if(p->v->storage_class==STATIC){
+ emit(f,"#%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"#%s%s",idprefix,p->v->identifier);
+ }
+ if(!zmeqto(l2zm(0L),p->val.vmax))
+ emit(f,"+%ld",(long)zm2l(p->val.vmax)*2);
+ }
+ }
+ if(p->flags®){
+ emit(f,"%s",regnames[p->reg]);
+ }
+ /* sometimes we just or a REG into a KONST */
+ if((p->flags&(KONST|REG))==KONST){
+ if(ISFLOAT(t)){
+ ierror(0);
+ emit(f,"#%s%d",labprefix,addfpconst(p,t));
+ }else{
+ emitval(f,&p->val,t&NU);
+ }
+ }
+}
+
+static void emit_lword(FILE *f,struct obj *p,int t,char *def)
+/* output low-word of an operand */
+{
+ if((p->flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->val,t);
+ if(ISFLOAT(t)){
+ unsigned char *ip=(unsigned char *)&vfloat;
+ emit(f,"0x%02x%02x",ip[1],ip[0]);
+ }else{
+ long v;
+ v=zm2l(vmax);
+ emit(f,"%ld",v&0xffff);
+ }
+ return;
+ }
+ if((p->flags&(REG|DREFOBJ))==REG){
+ if(!reg_pair(p->reg,&rp))
+ ierror(0);
+ emit(f,"%s",regnames[rp.r1]);
+ return;
+ }
+ if((p->flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ emit(f,def,regnames[p->reg]);
+ return;
+ }
+ ierror(0);
+}
+
+static void emit_hword(FILE *f,struct obj *p,int t,char *def)
+/* output high-word of an operand */
+{
+ if((p->flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->val,t);
+ if(ISFLOAT(t)){
+ unsigned char *ip=(unsigned char *)&vfloat;
+ emit(f,"0x%02x%02x",ip[3],ip[2]);
+ }else{
+ long v;
+ v=zm2l(vmax);
+ emit(f,"%ld",(v>>16)&0xffff);
+ }
+ return;
+ }
+ if((p->flags&(REG|DREFOBJ))==REG){
+ if(!reg_pair(p->reg,&rp))
+ ierror(0);
+ emit(f,"%s",regnames[rp.r2]);
+ return;
+ }
+ if((p->flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ emit(f,def,regnames[p->reg]);
+ return;
+ }
+ ierror(0);
+}
+
+static void cleanup_lword(FILE *f,struct obj *p)
+/* cleanup increased address pointers of emit_hlword */
+{
+ if((p->flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&!scratchreg(p->reg,icp))
+ emit(f,"\tsub\t2,%s\n",regnames[p->reg]);
+}
+
+static void pr(FILE *f,struct IC *p)
+{
+}
+
+static void function_top(FILE *f,struct Var *v,long offset)
+/* erzeugt Funktionskopf */
+{
+ int i,rcnt;char *tmp;
+
+ have_frame=0;stack_valid=1;
+ pushedsize=0;
+
+ if(!special_section(f,v)&§ion!=CODE){
+ emit(f,codename);
+ }
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else{
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }
+ if(stack_check){
+ stackchecklabel=++label;
+ BSET(regs_modified,t1);
+ emit(f,"\tmov\t%s,#%s%d\n",regnames[t1],labprefix,stackchecklabel);
+ emit(f,"\t%s\t%s__stack_check\n",call,idprefix);/*FIXME:usrstack*/
+ }
+ for(rcnt=0,i=1;i<=16;i++){
+ if(regused[i]&&!regscratch[i]&&!regsa[i])
+ rcnt++;
+ }
+ if(v->tattr&NORBANK) rcnt=0;
+ if(rcnt>((v->tattr&RBANK)?0:rwthreshold)){
+ /*emit(f,"\tadd\t256,%s\n",regnames[sr]);*/
+ emit(f,"\tincrb\n");
+ have_frame=3;
+ }else{
+ for(i=1;i<=16;i++){
+ if(regused[i]&&!regscratch[i]&&!regsa[i]){
+ emit(f,"\tmove\t%s,@--%s\n",regnames[i],regnames[sp]);
+ push(1);
+ have_frame=1;pushedsize+=1;
+ }
+ }
+ }
+ if(offset){
+ emit(f,"\tsub\t%ld,%s\n",offset,regnames[sp]);
+ if(!have_frame)
+ have_frame|=1;
+ }
+}
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/* erzeugt Funktionsende */
+{
+ int i;
+ if(offset) emit(f,"\tadd\t%ld,%s\n",offset,regnames[sp]);
+ if(have_frame==3){
+ /*emit(f,"\tsub\t256,%s\n",regnames[sr]);*/
+ emit(f,"\tdecrb\n");
+ }else{
+ for(i=16;i>0;i--){
+ if(regused[i]&&!regscratch[i]&&!regsa[i]){
+ emit(f,"\tmove\t@%s++,%s\n",regnames[sp],regnames[i]);
+ pop(1);
+ }
+ }
+ }
+ if(v->tattr&INTERRUPT){
+ emit(f,"\trti\n");
+ }else{
+ if(ret) emit(f,"\t%s\n",ret);
+ }
+ if(v->storage_class==EXTERN){
+ emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+ emit(f,"\t.size\t%s%s,$-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
+ }else{
+ emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset));
+ emit(f,"\t.size\t%s%ld,$-%s%ld\n",labprefix,zm2l(v->offset),labprefix,zm2l(v->offset));
+ }
+ if(stack_check)
+ emit(f,"%s%d\tequ\t%ld\n",labprefix,stackchecklabel,offset+pushedsize-maxpushed);
+ if(stack_valid){
+ long ustack=stack+offset+pushedsize;
+ if(!v->fi) v->fi=new_fi();
+ if(v->fi->flags&ALL_STACK){
+ if(v->fi->stack1!=stack)
+ if(f) error(319,"stack",ustack,v->fi->stack1);
+ }else{
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=stack;
+ }
+ emit(f,"\t.equ\t%s__ustack_%s,%ld\n",idprefix,v->identifier,zm2l(v->fi->stack1));
+ }
+}
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+ if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
+ return 1;
+ if((o1->flags&(KONST|VAR|DREFOBJ|REG|VARADR))==(o2->flags&(KONST|VAR|DREFOBJ|REG|VARADR))&&o1->am==o2->am){
+ if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+ if(!(o1->flags®)||o1->reg==o2->reg){
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+static void clear_ext_ic(struct ext_ic *p)
+{
+ p->flags=0;
+ p->r=0;
+ p->offset=0;
+}
+
+static void peephole(struct IC *p)
+{
+ int c,c2,r,t;struct IC *p2;
+ struct AddressingMode *am;
+ frame_used=0;
+ for(;p;p=p->next){
+ c=p->code;
+ if(!frame_used){
+ if((p->q1.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q1.v)) frame_used=1;
+ if((p->q2.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q2.v)) frame_used=1;
+ if((p->z.flags&(REG|VAR))==VAR&&!ISSTATIC(p->z.v)) frame_used=1;
+ }
+ /* letztes Label merken */
+ if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+ if(c==LABEL) exit_label=p->typf;
+
+ /* [Rx+] in q1 */
+ if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ r=p->q1.reg; t=q1typ(p);
+ if((!(p->q2.flags®)||p->q2.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if((c2==ADD||(c2==ADDI2P&&(p2->typf2&NQ)!=HPOINTER))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,p2->typf2);
+ if(zmeqto(vmax,l2zm(1L))&&ISHWORD(t)){
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ p->q1.am=mymalloc(sizeof(*am));
+ p->q1.am->flags=POST_INC;
+ p->q1.am->base=r;
+ }else break;
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(((p2->q1.flags®)&&p2->q1.reg==r)||((p2->q2.flags®)&&p2->q2.reg==r)||((p2->z.flags®)&&p2->z.reg==r)) break;
+ }
+ }
+ }
+ /* [Rx+] in q2 */
+ if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ r=p->q2.reg; t=q2typ(p);
+ if((!(p->q1.flags®)||p->q1.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if((c2==ADD||(c2==ADDI2P&&(p2->typf2&NQ)!=HPOINTER))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,p2->typf2);
+ if(zmeqto(vmax,l2zm(1L))&&ISHWORD(t)){
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ p->q2.am=mymalloc(sizeof(*am));
+ p->q2.am->flags=POST_INC;
+ p->q2.am->base=r;
+ }else break;
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(((p2->q1.flags®)&&p2->q1.reg==r)||((p2->q2.flags®)&&p2->q2.reg==r)||((p2->z.flags®)&&p2->z.reg==r)) break;
+ }
+ }
+ }
+ /* [Rx+] in z */
+ /* currently we do it only if q2 is empty; could be more clever */
+ if(!p->z.am&&!p->q2.flags&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ r=p->z.reg; t=ztyp(p);
+ if((!(p->q1.flags®)||p->q1.reg!=r)&&(!(p->q2.flags®)||p->q2.reg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if((c2==ADD||(c2==ADDI2P&&(p2->typf2&NQ)!=HPOINTER))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,p2->typf2);
+ if(zmeqto(vmax,l2zm(1L))&&ISHWORD(t)){
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ p->z.am=mymalloc(sizeof(*am));
+ p->z.am->flags=POST_INC;
+ p->z.am->base=r;
+ }else break;
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(((p2->q1.flags®)&&p2->q1.reg==r)||((p2->q2.flags®)&&p2->q2.reg==r)||((p2->z.flags®)&&p2->z.reg==r)) break;
+ }
+ }
+ }
+ /* --@Rx */
+ if(c==SUBIFP&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg&&p->q1.reg<=16&&isconst(q2)){
+ long sz;
+ r=p->q1.reg;
+ eval_const(&p->q2.val,q2typ(p));
+ sz=zm2l(vmax);
+ if(sz==1){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r&&(!(p2->q2.flags®)||p2->q2.reg!=r)&&(!(p2->z.flags®)||p2->z.reg!=r)&&(c2!=CONVERT||(q1typ(p2)&NQ)<=(ztyp(p2)&NQ))){
+ t=(q1typ(p2)&NQ);
+ if((ISINT(t)||ISPOINTER(t))&&ISHWORD(t)&&zmeqto(sizetab[q1typ(p2)&NQ],l2zm(sz))&&!islibcall(p2)){
+ p2->q1.am=am=mymalloc(sizeof(*am));
+ p2->q1.val.vmax=l2zm(0L);
+ am->base=r;
+ am->flags=PRE_DEC;
+ p->code=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ break;
+ }
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r&&(!(p2->q1.flags®)||p2->q1.reg!=r)&&(!(p2->z.flags®)||p2->z.reg!=r)){
+ t=(q2typ(p2)&NQ);
+ if((ISINT(t)||ISPOINTER(t))&&ISHWORD(t)&&zmeqto(sizetab[q2typ(p2)&NQ],l2zm(sz))&&!islibcall(p2)){
+ p2->q2.am=am=mymalloc(sizeof(*am));
+ p2->q2.val.vmax=l2zm(0L);
+ am->base=r;
+ am->flags=PRE_DEC;
+ p->code=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ break;
+ }
+ }
+ /* currently we do it only if q2 is empty; perhaps be more clever in the future */
+ if(!p2->z.am&&!p2->q2.flags&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r&&(!(p2->q2.flags®)||p2->q2.reg!=r)&&(!(p2->q1.flags®)||p2->q1.reg!=r)){
+ t=(ztyp(p2)&NQ);
+ if((ISINT(t)||ISPOINTER(t))&&ISHWORD(t)&&zmeqto(sizetab[ztyp(p2)&NQ],l2zm(sz))&&!islibcall(p2)){
+ p2->z.am=am=mymalloc(sizeof(*am));
+ p2->z.val.vmax=l2zm(0L);
+ am->base=r;
+ am->flags=PRE_DEC;
+ p->code=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ break;
+ }
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if((p2->q1.flags®)&&p2->q1.reg==r) break;
+ if((p2->q2.flags®)&&p2->q2.reg==r) break;
+ if((p2->z.flags®)&&p2->z.reg==r) break;
+ }
+ }
+ }
+ }
+}
+
+static struct obj *cam(int flags,int base,long offset,struct Var *v)
+/* Initializes an addressing-mode structure and returns a pointer to */
+/* that object. Will not survive a second call! */
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ return &obj;
+}
+
+
+/* load an operand if necessary, use register r if needed */
+static void load_op(FILE *f,struct obj *o,int t,int r)
+{
+ if(o->am)
+ return;
+
+ if(o->flags&(REG|VARADR))
+ return;
+
+ if(o->flags&KONST){
+ if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE){
+ int l=addfpconst(o,t);
+ emit(f,"\tmove\t%s%d,%s\n",labprefix,l,regnames[r]);
+ o->reg=r;
+ o->flags=REG|DREFOBJ;
+ }else if(load_const||(o->flags&DREFOBJ)){
+ emit(f,"\tmove\t");
+ emit_obj(f,o,t);
+ emit(f,",%s\n",regnames[r]);
+ o->flags|=REG;
+ o->flags&=~KONST;
+ }else
+ return;
+ }else{
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+ if(ISHWORD(t)&&voff(o)==0){
+ if(o->flags&DREFOBJ){
+ emit(f,"\tmove\t@%s,%s\n",regnames[sp],regnames[r]);
+ o->reg=r;
+ o->flags|=REG|DREFOBJ;
+ BSET(regs_modified,r);
+ return;
+ }else
+ r=sp;
+ }else{
+ emit(f,"\tmove\t%s,%s\n",regnames[sp],regnames[r]);
+ if(voff(o))
+ emit(f,"\tadd\t%ld,%s\n",voff(o),regnames[r]);
+ }
+
+ }else{
+ emit(f,"\tmove\t");
+ emit_obj(f,o,t);
+ emit(f,",%s\n",regnames[r]);
+ }
+
+
+ if(o->flags&DREFOBJ){
+ emit(f,"\tmove\t@%s,%s\n",regnames[r],regnames[r]);
+ }
+
+ o->flags|=REG|DREFOBJ;
+ }
+
+ BSET(regs_modified,r);
+ o->reg=r;
+}
+
+static void move(FILE *f,struct obj *q,int qr,struct obj *z,int zr,int t)
+/* Generates code to move object q (or register qr) into object z (or */
+/* register zr). One must be a register and DREFOBJ only allowed with */
+/* registers. */
+{
+ if(q&&z&&compare_objects(q,z))
+ return;
+
+ if(q&&(q->flags&(REG|DREFOBJ))==REG) qr=q->reg;
+ if(z&&(z->flags&(REG|DREFOBJ))==REG) zr=z->reg;
+
+ if(qr&&qr==zr)
+ return;
+
+
+ if(ISLWORD(t)){
+ if(!qr) load_op(f,q,t,t1);
+ if(!zr) load_op(f,z,t,t2);
+
+ emit(f,"\tmove\t");
+ if(qr&®_pair(qr,&rp))
+ emit(f,"%s",regnames[rp.r1]);
+ else
+ emit_lword(f,q,t,"@%s++");
+ emit(f,",");
+ if(zr&®_pair(zr,&rp))
+ emit(f,"%s",regnames[rp.r1]);
+ else
+ emit_lword(f,z,t,"@%s++");
+ emit(f,"\n");
+ emit(f,"\tmove\t");
+ if(qr&®_pair(qr,&rp))
+ emit(f,"%s",regnames[rp.r2]);
+ else
+ emit_hword(f,q,t,"@%s++");
+ emit(f,",");
+ if(zr&®_pair(zr,&rp))
+ emit(f,"%s",regnames[rp.r2]);
+ else
+ emit_hword(f,z,t,"@%s++");
+ emit(f,"\n");
+ if(!qr) cleanup_lword(f,q);
+ if(!zr) cleanup_lword(f,z);
+ return;
+ }
+
+
+ emit(f,"\tmove\t");
+ if(qr) emit(f,"%s",regnames[qr]); else emit_obj(f,q,t);
+ emit(f,",");
+ if(zr) emit(f,"%s",regnames[zr]); else emit_obj(f,z,t);
+ emit(f,"\n");
+}
+
+static int get_reg(FILE *f,struct IC *p)
+{
+ int i;
+ for(i=1;i<=16;i++){
+ if(!regs[i]&&(regscratch[i]||regused[i])&&!regsa[i]){
+ BSET(regs_modified,i);
+ return i;
+ }
+ }
+ return 0;
+}
+
+
+
+static void save_result(FILE *f,int r,struct IC *p,int t)
+/* Saves result in register r to object o. May use tp or ti. */
+{
+ ierror(0);
+}
+
+static int scratchreg(int r,struct IC *p)
+{
+ int c;
+ if(r==t1||r==t2)
+ return 1;
+ while(1){
+ p=p->next;
+ if(!p||((c=p->code)==FREEREG&&p->q1.reg==r)) return 1;
+ if(c==CALL||(c>=BEQ&&c<=BRA)) return 0;
+ if((p->q1.flags®)&&p->q1.reg==r) return 0;
+ if((p->q2.flags®)&&p->q2.reg==r) return 0;
+ if((p->z.flags®)&&p->z.reg==r) return 0;
+ }
+}
+
+/****************************************/
+/* End of private fata and functions. */
+/****************************************/
+
+int emit_peephole(void)
+{
+ int entries,i,r1,r2,r3,r4;long x,y,z;
+ char *asmline[EMIT_BUF_DEPTH];
+ char s1[16],s2[16];
+
+ if(NOPEEP)
+ return 0;
+
+ i=emit_l;
+ if(emit_f==0)
+ entries=i-emit_f+1;
+ else
+ entries=EMIT_BUF_DEPTH;
+ asmline[0]=emit_buffer[i];
+
+ if(entries>=1){
+ if(sscanf(asmline[0],"\tmove\t0,R%d",&r1)==1){
+ sprintf(asmline[0],"\txor\tR%d,R%d\n",r1,r1);
+ return 1;
+ }
+ }
+
+ if(entries>=2){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[1]=emit_buffer[i];
+ if(sscanf(asmline[0],"\t%15s\t%ld,R%d",s1,&x,&r1)==3&&sscanf(asmline[1],"\t%15s\t%ld,R%d",s2,&y,&r2)==3&&r1==r2&&!strcmp(s1,s2)&&(!strcmp(s1,"add")||!strcmp(s1,"sub")||!strcmp(s1,"shl")||!strcmp(s1,"shr"))){
+ sprintf(asmline[1],"\t%s\t%ld,R%d\n",s1,x+y,r1);
+ remove_asm();
+ return 1;
+ }
+ if(sscanf(asmline[0],"\t%15s\t%ld,@R%d",s1,&x,&r1)==3&&sscanf(asmline[1],"\t%15s\t%ld,@R%d",s2,&y,&r2)==3&&r1==r2&&!strcmp(s1,s2)&&(!strcmp(s1,"add")||!strcmp(s1,"sub")||!strcmp(s1,"shl")||!strcmp(s1,"shr"))){
+ sprintf(asmline[1],"\t%s\t%ld,@R%d\n",s1,x+y,r1);
+ remove_asm();
+ return 1;
+ }
+ if(sscanf(asmline[0],"\tmove\tR%d,R%d",&r1,&r2)==2&&sscanf(asmline[1],"\tmove\tR%d,R%d",&r3,&r4)==2&&r1==r4&&r2==r3){
+ remove_asm();
+ return 1;
+ }
+ if(sscanf(asmline[0],"\tshl\t1,R%d",&r1)==1&&!strstr(asmline[0],"shr")){
+ sprintf(asmline[0],"\tadd\tR%d,R%d\n",r1,r1);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int init_cg(void)
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(1L);
+ stackalign=l2zm(1L);
+ char_bit=l2zm(16L);
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+ for(i=1;i<=MAXR;i++){
+ if(i<=16){
+ regsize[i]=l2zm(1L);regtype[i]=&ityp;
+ }else{
+ regsize[i]=l2zm(2L);regtype[i]=<yp;
+ }
+ }
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-32768L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=t_min[SHORT];
+ t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(32767UL);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=t_max[SHORT];
+ t_max[LONG]=ul2zum(2147483647UL);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(65535UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=tu_max[SHORT];
+ tu_max[LONG]=ul2zum(4294967295UL);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ regsa[sp]=regsa[sr]=regsa[pc]=regsa[t1]=regsa[t2]=regsa[MTMP1]=1;
+ regscratch[sp]=regscratch[sr]=regscratch[pc]=regscratch[t1]=regscratch[t2]=0;
+ target_macros=marray;
+ if(TINY) marray[0]="__TINY__";
+ else if(LARGE) marray[0]="__LARGE__";
+ else if(HUGE) marray[0]="__HUGE__";
+ else marray[0]="__MEDIUM__";
+
+ /*static_cse=0;*/
+ dref_cse=0;
+
+ if(g_flags[9]&USEDFLAG)
+ rwthreshold=g_flags_val[9].l;
+ else{
+ if(optspeed)
+ rwthreshold=1;
+ else
+ rwthreshold=2;
+ }
+
+ /* TODO: set argument registers */
+ declare_builtin("__mulint32",LONG,LONG,r8r9,LONG,0,1,0);
+ declare_builtin("__divint32",LONG,LONG,r8r9,LONG,0,1,0);
+ declare_builtin("__divuint32",LONG,LONG,r8r9,LONG,0,1,0);
+ declare_builtin("__modint32",LONG,LONG,r8r9,LONG,0,1,0);
+ declare_builtin("__moduint32",LONG,LONG,r8r9,LONG,0,1,0);
+ declare_builtin("__lslint32",LONG,LONG,r8r9,INT,11,1,0);
+ declare_builtin("__lsrint32",LONG,LONG,r8r9,INT,11,1,0);
+ declare_builtin("__lsruint32",LONG,LONG,r8r9,INT,11,1,0);
+
+ declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+ declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+ declare_builtin("__divint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__modint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__lsrint64",LLONG,LLONG,0,INT,0,1,0);
+ declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+ declare_builtin("__cmpint64",INT,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+
+ declare_builtin("__sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
+ declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
+ declare_builtin("__sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
+ declare_builtin("__uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
+ declare_builtin("__flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
+ declare_builtin("__flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);
+
+ declare_builtin("__sint32toflt32",FLOAT,LONG,r8r9,0,0,1,0);
+ declare_builtin("__uint32toflt32",FLOAT,UNSIGNED|LONG,r8r9,0,0,1,0);
+ declare_builtin("__sint32toflt64",DOUBLE,LONG,0,0,0,1,0);
+ declare_builtin("__uint32toflt64",DOUBLE,UNSIGNED|LONG,0,0,0,1,0);
+ declare_builtin("__flt32tosint32",LONG,FLOAT,r8r9,0,0,1,0);
+ declare_builtin("__flt32touint32",UNSIGNED|LONG,FLOAT,r8r9,0,0,1,0);
+ declare_builtin("__flt64tosint32",LONG,DOUBLE,0,0,0,1,0);
+ declare_builtin("__flt64touint32",UNSIGNED|LONG,DOUBLE,0,0,0,1,0);
+
+ declare_builtin("__sint16toflt32",FLOAT,INT,r8,0,0,1,0);
+ declare_builtin("__uint16toflt32",FLOAT,UNSIGNED|INT,r8,0,0,1,0);
+ declare_builtin("__sint16toflt64",DOUBLE,INT,r9,0,0,1,0);
+ declare_builtin("__uint16toflt64",DOUBLE,UNSIGNED|INT,r9,0,0,1,0);
+ declare_builtin("__flt32tosint16",INT,FLOAT,r8r9,0,0,1,0);
+ declare_builtin("__flt32touint16",UNSIGNED|INT,FLOAT,r8r9,0,0,1,0);
+ declare_builtin("__flt64tosint16",INT,DOUBLE,0,0,0,1,0);
+ declare_builtin("__flt64touint16",UNSIGNED|INT,DOUBLE,0,0,0,1,0);
+
+
+
+
+ declare_builtin("__flt32toflt64",DOUBLE,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt64toflt32",FLOAT,DOUBLE,0,0,0,1,0);
+
+
+ declare_builtin("__addflt32",FLOAT,FLOAT,r8r9,FLOAT,0,1,0);
+ declare_builtin("__subflt32",FLOAT,FLOAT,r8r9,FLOAT,0,1,0);
+ declare_builtin("__mulflt32",FLOAT,FLOAT,r8r9,FLOAT,0,1,0);
+ declare_builtin("__divflt32",FLOAT,FLOAT,r8r9,FLOAT,0,1,0);
+ declare_builtin("__negflt32",FLOAT,FLOAT,r8r9,0,0,1,0);
+ declare_builtin("__cmpsflt32",INT,FLOAT,r8r9,FLOAT,0,1,0);
+
+ declare_builtin("__addflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__subflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__mulflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__divflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__negflt64",DOUBLE,DOUBLE,0,0,0,1,0);
+ declare_builtin("__cmpsflt64",INT,DOUBLE,0,DOUBLE,0,1,0);
+
+ return 1;
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+{
+ int f=t->flags&NQ;
+ if(f==LLONG||f==DOUBLE||f==LDOUBLE)
+ return 0;
+ if(ISSCALAR(f)){
+ if(f==LONG||f==FPOINTER||f==HPOINTER||f==FLOAT)
+ return r8r9;
+ else
+ return r8;
+ }
+ return 0;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ t&=NQ;
+ if(r==0) return(0);
+ if((t<LONG||t==NPOINTER)&&r<=16) return 1;
+ if(t==LONG||t==FLOAT||t==FPOINTER||t==HPOINTER){
+ if(r>16) return 1;
+ }
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ if(r<=16) return 0;
+ if(p){
+ switch(r){
+ case 17: p->r1=1;p->r2=2;break;
+ case 18: p->r1=3;p->r2=4;break;
+ case 19: p->r1=5;p->r2=6;break;
+ case 20: p->r1=7;p->r2=8;break;
+ case 21: p->r1=9;p->r2=10;break;
+ case 22: p->r1=t1;p->r2=t2;break;
+
+ default: ierror(0);
+ }
+ }
+ return 1;
+}
+
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+ int c=p->code;
+ if((o->flags&DREFOBJ)){
+ if(o->flags&VKONST) return 1;
+ if(r<=4&&p->q2.flags&&o!=&p->z)
+ return 6;
+ else
+ return 4;
+ }else if(o->flags&VKONST){
+ struct obj *co=&o->v->cobj;
+ if((p->code==ASSIGN&&(p->z.flags&DREFOBJ))||p->code==PUSH)
+ return 4;
+ if(co->flags&VARADR)
+ return 4;
+ if(o==&p->q1)
+ eval_const(&co->val,q1typ(p));
+ else
+ eval_const(&co->val,q2typ(p));
+ /*FIXME*/
+ return 0;
+ }else if(c==GETRETURN&&p->q1.reg==r){
+ return 4;
+ }else if(c==SETRETURN&&p->z.reg==r){
+ return 4;
+ }else if(c==CONVERT&&((p->typf&NQ)==CHAR||(p->typf2&NQ)==CHAR)&®ok(r,CHAR,0)){
+ return 3;
+ }
+ return 2;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* In this generic 32bit RISC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op=o&NQ,tp=t&NQ;
+ if(op==tp) return 0;
+ if(ISHWORD(op)&&ISHWORD(tp)) return 0;
+ if(ISFLOAT(op)||ISFLOAT(tp)) return 1;
+ if(ISLWORD(op)&&ISLWORD(tp)) return 0;
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ long l=zm2l(size)*2;
+ if(newobj&§ion!=SPECIAL)
+ emit(f,"%ld\n",l);
+ else
+ emit(f,"\t.space\t%ld\n",l);
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+}
+static void new_section(FILE *f,int nsec)
+{
+ if(!f||section==nsec) return;
+ section=nsec;
+ if(nsec==HDATA){
+ emit(f,hdataname);
+ }else if(nsec==FDATA){
+ emit(f,fdataname);
+ }else if(nsec==NDATA){
+ emit(f,ndataname);
+ }else if(nsec==HCDATA){
+ emit(f,hcdataname);
+ }else if(nsec==FCDATA){
+ emit(f,fcdataname);
+ }else if(nsec==NCDATA){
+ emit(f,ncdataname);
+ }else if(nsec==HBSS){
+ emit(f,hbssname);
+ }else if(nsec==FBSS){
+ emit(f,fbssname);
+ }else if(nsec==NBSS){
+ emit(f,nbssname);
+ }
+}
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;
+ char *attr;struct Typ *tv;
+ tv=v->vtyp;
+ while(tv->flags==ARRAY) tv=tv->next;
+ attr=tv->attr;
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset));
+ emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp))*2);
+ if(!special_section(f,v)){
+ if((v->vtyp->flags&NQ)==BIT){
+ new_section(f,BITS);
+ }else{
+ if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))){
+ if(attr&&strstr(attr,STR_HUGE))
+ new_section(f,HDATA);
+ else if(attr&&strstr(attr,STR_FAR))
+ new_section(f,FDATA);
+ else if(attr&&strstr(attr,STR_NEAR))
+ new_section(f,NDATA);
+ else{
+ if(HUGE)
+ new_section(f,HDATA);
+ else if(LARGE)
+ new_section(f,FDATA);
+ else
+ new_section(f,NDATA);
+ }
+ }
+ if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)){
+ if(attr&&strstr(attr,STR_HUGE))
+ new_section(f,HCDATA);
+ else if(attr&&strstr(attr,STR_FAR))
+ new_section(f,FCDATA);
+ else if(attr&&strstr(attr,STR_NEAR))
+ new_section(f,NCDATA);
+ else{
+ if(HUGE)
+ new_section(f,HCDATA);
+ else if(LARGE)
+ new_section(f,FCDATA);
+ else
+ new_section(f,NCDATA);
+ }
+ }
+ if(!v->clist){
+ if(attr&&strstr(attr,STR_HUGE))
+ new_section(f,HBSS);
+ else if(attr&&strstr(attr,STR_FAR))
+ new_section(f,FBSS);
+ else if(attr&&strstr(attr,STR_NEAR))
+ new_section(f,NBSS);
+ else{
+ if(HUGE)
+ new_section(f,HBSS);
+ else if(LARGE)
+ new_section(f,FBSS);
+ else
+ new_section(f,NBSS);
+ }
+ }
+ }
+ }
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }
+
+ if(v->storage_class==EXTERN){
+ if(v->flags&(DEFINED|TENTATIVE)){
+ emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
+ emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp))*2);
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))){
+ if(attr&&strstr(attr,STR_HUGE))
+ new_section(f,HDATA);
+ else if(attr&&strstr(attr,STR_FAR))
+ new_section(f,FDATA);
+ else if(attr&&strstr(attr,STR_NEAR))
+ new_section(f,NDATA);
+ else{
+ if(HUGE)
+ new_section(f,HDATA);
+ else if(LARGE)
+ new_section(f,FDATA);
+ else
+ new_section(f,NDATA);
+ }
+ }
+ if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)){
+ if(attr&&strstr(attr,STR_HUGE))
+ new_section(f,HCDATA);
+ else if(attr&&strstr(attr,STR_FAR))
+ new_section(f,FCDATA);
+ else if(attr&&strstr(attr,STR_NEAR))
+ new_section(f,NCDATA);
+ else{
+ if(HUGE)
+ new_section(f,HCDATA);
+ else if(LARGE)
+ new_section(f,FCDATA);
+ else
+ new_section(f,NCDATA);
+ }
+ }
+ if(!v->clist){
+ if(attr&&strstr(attr,STR_HUGE))
+ new_section(f,HBSS);
+ else if(attr&&strstr(attr,STR_FAR))
+ new_section(f,FBSS);
+ else if(attr&&strstr(attr,STR_NEAR))
+ new_section(f,NBSS);
+ else{
+ if(HUGE)
+ new_section(f,HBSS);
+ else if(LARGE)
+ new_section(f,FBSS);
+ else
+ new_section(f,NBSS);
+ }
+ }
+ }
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else if(strcmp(v->identifier,"__va_start")){
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ if(ISPOINTER(t)){
+ if(p->tree)
+ emit(f,"\t%s\t",dct[t&NQ]);
+ if(ISLWORD(t))
+ t=UNSIGNED|LONG;
+ else
+ t=UNSIGNED|SHORT;
+ if(!p->tree)
+ emit(f,"\t%s\t",dct[t&NQ]);
+ }else{
+ emit(f,"\t%s\t",dct[t&NQ]);
+ }
+ if(!p->tree){
+ if(ISFLOAT(t)){
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x,0x%02x%02x",ip[1],ip[0],ip[3],ip[2]);
+ if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE){
+ emit(f,",0x%02x%02x,0x%02x%02x",ip[5],ip[4],ip[7],ip[6]);
+ }
+ }else{
+ if(ISLWORD(t)){
+ long l;
+ eval_const(&p->val,t);
+ l=zm2l(zmand(p->val.vmax,l2zm(65535L)));
+ emit(f,"%ld",l);
+ l=zm2l(zmand(zmrshift(p->val.vmax,l2zm(16L)),l2zm(65535L)));
+ emit(f,",%ld",l);
+ }else
+ emitval(f,&p->val,(t&NU)|UNSIGNED);
+ }
+ }else{
+ int m=p->tree->o.flags;
+ p->tree->o.flags&=~VARADR;
+ emit_obj(f,&p->tree->o,t&NU);
+ p->tree->o.flags=m;
+ }
+ emit(f,"\n");
+}
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+{
+ int c,t,lastcomp=0,cmpzero=0,elab=0,reg,short_add,bit_reverse,need_return=0;
+ struct obj *bit_obj;char *bit_reg;
+ static int idone;
+ struct obj o,*cc=0;int cc_t;
+ struct IC *p2;
+ if(TINY){
+ call="asub";
+ jump="abra";
+ }else{
+ call="asub";
+ jump="abra";
+ }
+ if(v->tattr&INTERRUPT){
+ ret="rti";
+ need_return=1;
+ }else
+ ret="move\t@R13++,R15";
+
+ if(DEBUG&1) printf("gen_code()\n");
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_REGS;
+
+ for(p2=p;p2;p2=p2->next) clear_ext_ic(&p2->ext);
+ if(!(g_flags[5]&USEDFLAG)){
+ peephole(p);
+ if(!frame_used) offset=l2zm(0L);
+ }
+ for(c=1;c<=15;c++) regs[c]=regsa[c];
+ regs[16]=0;
+ for(c=1;c<=MAXR;c++){
+ if(regscratch[c]&&(regsa[c]||regused[c])){
+ BSET(regs_modified,c);
+ }
+ }
+ loff=zm2l(offset);
+ function_top(f,v,loff);
+ stackoffset=notpopped=dontpop=maxpushed=0;
+ stack=0;
+ for(;p;pr(f,p),p=p->next){
+ c=p->code;t=p->typf;
+ t2_used=0; short_add=0;
+ icp=p;
+ if(c==NOP) continue;
+ if(c==ALLOCREG){
+ regs[p->q1.reg]=1;
+ if(reg_pair(p->q1.reg,&rp)) regs[rp.r1]=regs[rp.r2]=1;
+ BSET(regs_modified,p->q1.reg);
+ continue;
+ }
+ if(c==FREEREG){
+ regs[p->q1.reg]=0;
+ if(reg_pair(p->q1.reg,&rp)) regs[rp.r1]=regs[rp.r2]=0;
+ continue;
+ }
+ if(notpopped&&!dontpop){
+ int flag=0;
+ if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+ emit(f,"\tadd\t%ld,%s\n",notpopped,regnames[sp]);
+ pop(notpopped);notpopped=0;cc=0;
+ }
+ }
+ if(c==LABEL) {cc=0;emit(f,"%s%d:\n",labprefix,t);continue;}
+ if(c==BRA){
+ if(p->typf==exit_label&&!have_frame){
+ emit(f,"\t%s\n",ret);
+ }else{
+ if(t==exit_label) need_return=1;
+ emit(f,"\trbra\t%s%d,1\n",labprefix,t);
+ }
+ cc=0;continue;
+ }
+ if(c>=BEQ&&c<BRA){
+ char *s=0;
+ cc=0;
+ if(cmpzero){
+ cmpzero=0;
+ if(lastcomp&UNSIGNED){
+ if(c==BLT) continue;
+ if(c==BGE) s="1";
+ if(c==BLE) s="z";
+ if(c==BGT) s="!z";
+ }else{
+ if(c==BLT) s="n";
+ if(c==BGE) s="!n";
+ if(c==BLE) ierror(0);
+ if(c==BGT) ierror(0);
+ }
+ }
+ if(!s){
+ if(lastcomp&UNSIGNED) s=ccu[c-BEQ]; else s=ccs[c-BEQ];
+ }
+ if(t==exit_label&&!have_frame){
+ emit(f,"\tabra\t@%s++,%s\n",regnames[sp],s);
+ }else{
+ emit(f,"\trbra\t%s%d,%s\n",labprefix,t,s);
+ if(t==exit_label) need_return=1;
+ }
+ continue;
+ }
+ if(c==MOVETOREG){
+ load_op(f,&p->q1,SHORT,t1);
+ if(p->z.reg<=16){
+ move(f,&p->q1,0,0,p->z.reg,SHORT);
+ cc=&p->q1;cc_t=SHORT;
+ }else{
+ move(f,&p->q1,0,0,p->z.reg,LONG);
+ cc=0;
+ }
+ continue;
+ }
+ if(c==MOVEFROMREG){
+ load_op(f,&p->z,SHORT,t2);
+ if(p->q1.reg<=16){
+ move(f,0,p->q1.reg,&p->z,0,SHORT);
+ cc=&p->z;cc_t=SHORT;
+ }else{
+ move(f,0,p->q1.reg,&p->z,0,LONG);
+ cc=0;
+ }
+ continue;
+ }
+
+ if(c==TEST){
+ /* TODO: optimize in COMPARE? */
+ lastcomp=t;
+ if(cc&&(cc_t&NU)==(t&NU)&&compare_objects(cc,&p->q1)){
+ continue;
+ }
+
+ p->code=c=COMPARE;
+ gval.vmax=l2zm(0L);
+ p->q2.flags=KONST;
+ eval_const(&gval,MAXINT);
+ insert_const(&p->q2.val,t);
+ }
+ /* switch operands so that we have matching branch */
+ if(c==COMPARE){
+ p2=p->next;
+ while(p2&&p2->code==FREEREG) p2=p2->next;
+ if(!p2||p2->code<BEQ||p2->code>BGT) ierror(0);
+ if(p2->code==BGT){
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ p2->code=BLT;
+ }else if(p2->code==BLE){
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ p2->code=BGE;
+ }
+ }
+
+ if(c==COMPARE&&isconst(q2)){
+ eval_const(&p->q2.val,t);
+ if(ISNULL()){
+ if(cc&&(cc_t&NU)==(t&NU)&&compare_objects(cc,&p->q1)){
+ p2=p->next;
+ while(p2&&p2->code==FREEREG) p2=p2->next;
+ if(!p2||p2->code<BEQ||p2->code>BGT) ierror(0);
+ if((t&UNSIGNED)||p2->code==BNE||p2->code==BEQ||p2->code==BLT||p2->code==BGE){
+ lastcomp=t;
+ cmpzero=1;
+ continue;
+ }
+ }
+ }
+ }
+
+ if(c==SUBPFP){
+ p->code=c=SUB;
+ if((p->typf2&NQ)==NPOINTER) p->typf=t=INT;
+ else if((p->typf2&NQ)==HPOINTER) p->typf=t=LONG;
+ else ierror(0);
+ if((p->typf2&NQ)==NPOINTER){
+ cc=&p->z;cc_t=NPOINTER;
+ }else{
+ cc=0;
+ }
+ }
+
+ if(c==ADDI2P||c==SUBIFP){
+ /*if(c==ADDI2P) p->code=c=ADD; else p->code=c=SUB;*/
+ if((p->typf2&NQ)!=HPOINTER){
+ p->typf=t=(UNSIGNED|SHORT);
+ short_add=2;
+ if(isreg(q2)&®_pair(p->q2.reg,&rp)){
+ /*FIXME:warning*/
+ p->q2.reg=rp.r1;
+ }
+ }else if(ISHWORD(t)){
+ p->typf=t=(UNSIGNED|LONG);
+ short_add=1;
+ }
+ if((p->typf2&NQ)==NPOINTER){
+ cc=&p->z;cc_t=NPOINTER;
+ }else{
+ cc=0;
+ }
+ }
+
+ if(c==CONVERT&&!must_convert(p->typf,p->typf2,0)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=sizetab[p->typf&NQ];
+ }
+
+ if(c==CONVERT){
+ int to=p->typf2&NU;
+ if(to==INT||to==CHAR) to=SHORT;
+ if(to==(UNSIGNED|INT)||to==(UNSIGNED|CHAR)||to==NPOINTER) to=(UNSIGNED|SHORT);
+ if(to==FPOINTER||to==HPOINTER) to=(UNSIGNED|LONG);
+ if((t&NU)==INT||(t&NU)==CHAR) t=SHORT;
+ if((t&NU)==(UNSIGNED|INT)||(t&NU)==(UNSIGNED|CHAR)||(t&NU)==NPOINTER) t=(UNSIGNED|SHORT);
+ if((t&NQ)==FPOINTER||(t&NQ)==HPOINTER) t=(UNSIGNED|LONG);
+ if((to&NQ)==LONG){
+ if((t&NQ)!=SHORT) ierror(0);
+ load_op(f,&p->q1,to,t1);
+ load_op(f,&p->z,t,t2);
+ if(isreg(q1)){
+ if(!reg_pair(p->q1.reg,&rp))
+ ierror(0);
+ move(f,0,rp.r1,&p->z,0,t);
+ }else
+ move(f,&p->q1,0,&p->z,0,t);
+ cc=&p->z;cc_t=t;
+ continue;
+ }else if((t&NQ)==LONG){
+ if((to&NQ)!=SHORT) ierror(0);
+ load_op(f,&p->q1,to,t1);
+ load_op(f,&p->z,t,t2);
+ if(isreg(z)){
+ if(!reg_pair(p->z.reg,&rp))
+ ierror(0);
+ emit(f,"\txor\t%s,%s\n",regnames[rp.r2],regnames[rp.r2]);
+ move(f,&p->q1,0,0,rp.r1,to);
+ if(!(to&UNSIGNED)){
+ emit(f,"\trbra\t%s%d,!n\n",labprefix,++label);
+ emit(f,"\tsub\t1,%s\n",regnames[rp.r2]);
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ }else{
+ if(to&UNSIGNED){
+ emit(f,"\tmove\t");
+ emit_obj(f,&p->q1,to);
+ emit(f,",@%s++\n",regnames[p->z.reg]);
+ emit(f,"\tmove\t0,@%s\n",regnames[p->z.reg]);
+ }else{
+ if(isreg(q1)){
+ reg=p->q1.reg;
+ }else{
+ reg=t1;
+ move(f,&p->q1,0,0,t1,to);
+ }
+ emit(f,"\tmove\t%s,@%s++\n",regnames[reg],regnames[p->z.reg]);
+ emit(f,"\tmove\t0,@%s\n",regnames[p->z.reg]);
+ emit(f,"\tmove\t%s,%s\n",regnames[reg],regnames[reg]);
+ emit(f,"\trbra\t%s%d,!n\n",labprefix,++label);
+ emit(f,"\tsub\t1,@%s\n",regnames[p->z.reg]);
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ if(!scratchreg(p->z.reg,p))
+ emit(f,"\tsub\t1,%s\n",regnames[p->z.reg]);
+ }
+ cc=0;
+ continue;
+ }else
+ ierror(0);
+ }
+ if(c==MINUS){
+ p->code=c=SUB;
+ p->q2=p->q1;
+ gval.vmax=l2zm(0L);
+ eval_const(&gval,t);
+ insert_const(&p->q1.val,t);
+ p->q1.flags=KONST;
+ }
+ if(c==KOMPLEMENT){
+ load_op(f,&p->q1,t,t1);
+ load_op(f,&p->z,t,t2);
+ if(ISLWORD(t)){
+ emit(f,"\tnot\t");
+ emit_lword(f,&p->q1,t,"@%s++");
+ emit(f,",");
+ emit_lword(f,&p->z,t,"@%s++");
+ emit(f,"\n");
+ emit(f,"\tnot\t");
+ emit_hword(f,&p->q1,t,"@%s++");
+ emit(f,",");
+ emit_hword(f,&p->z,t,"@%s++");
+ emit(f,"\n");
+ cleanup_lword(f,&p->q1);
+ cleanup_lword(f,&p->z);
+ cc=0;
+ }else{
+ emit(f,"\tnot\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,",");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ cc=&p->z;cc_t=t;
+ }
+ continue;
+ }
+ if(c==SETRETURN){
+ if(p->z.reg){
+ if(reg_pair(p->z.reg,&rp))
+ load_op(f,&p->q1,t,t1);
+ else
+ load_op(f,&p->q1,t,p->z.reg);
+ move(f,&p->q1,0,0,p->z.reg,t);
+ BSET(regs_modified,p->z.reg);
+ }
+ cc=0; /* probably not needed */
+ continue;
+ }
+ if(c==GETRETURN){
+ if(p->q1.reg){
+ if((!isreg(z)||p->z.reg!=p->q1.reg)&&!ISLWORD(t)){ cc=&p->z;cc_t=t;}
+ load_op(f,&p->z,t,t2);
+ move(f,0,p->q1.reg,&p->z,0,t);
+ }
+ continue;
+ }
+ if(c==CALL){
+ int reg,jmp=0;long cstack=0;
+ cc=0;
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+ long va_off=loff-stackoffset+pushedsize+zm2l(va_offset(v))+1;
+ emit(f,"\tmove\t%s,%s\n",regnames[sp],regnames[r8]);
+ if(va_off)
+ emit(f,"\tadd\t%ld,%s\n",va_off,regnames[r8]);
+ BSET(regs_modified,r8);
+ if(LARGE||HUGE){
+ emit(f,"\tmove\t0,%s\n",regnames[r9]);
+ BSET(regs_modified,r9);
+ }
+ continue;
+ }
+ if(stack_valid){
+ int i;
+ if(p->call_cnt<=0){
+ err_ic=p;if(f) error(320);
+ stack_valid=0;
+ }
+ for(i=0;stack_valid&&i<p->call_cnt;i++){
+ if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_STACK)){
+ if(p->call_list[i].v->fi->stack1>cstack) cstack=p->call_list[i].v->fi->stack1;
+ }else{
+ err_ic=p;if(f) error(317,p->call_list[i].v->identifier);
+ stack_valid=0;
+ }
+ }
+ }
+ if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS;
+ if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ callee_push(cstack);
+ }else{
+ if(stackoffset==0&&!have_frame&&!(v->tattr&INTERRUPT)){
+ struct IC *p2;
+ jmp=1;
+ for(p2=p->next;p2;p2=p2->next){
+ if(p2->code!=FREEREG&&p2->code!=ALLOCREG&&p2->code!=LABEL&&p2->code!=NOP&&
+ (p2->code!=GETRETURN||(p2->z.flags&(REG|DREFOBJ))!=REG||p2->q1.reg!=p2->z.reg)&&
+ (p2->code!=SETRETURN||(p2->q1.flags&(REG|DREFOBJ))!=REG||p2->q1.reg!=p2->z.reg)){
+ jmp=0;break;
+ }
+ }
+ }
+ if(p->q1.flags&DREFOBJ){
+ int clabel=++label;
+ if(ISLWORD(p->q1.dtyp)){
+ ierror(0);
+ }
+ p->q1.flags&=~DREFOBJ;
+ load_op(f,&p->q1,t,t1);
+ if(!ISLWORD(p->q1.dtyp)){
+ emit(f,"\t%s\t",jmp?jump:"asub");
+ emit_obj(f,&p->q1,p->q1.dtyp);
+ emit(f,",1\n");
+ push(1);
+ callee_push(cstack);
+ pop(1);
+ }else{
+ ierror(0);
+ }
+ }else{
+ if(jmp){
+ emit(f,"\t%s\t",jump);
+ callee_push(cstack);
+ }else{
+ emit(f,"\t%s\t",call);
+ if(TINY)
+ push(1);
+ else
+ push(2);
+ callee_push(cstack);
+ if(TINY)
+ pop(1);
+ else
+ pop(2);
+ }
+ emit_obj(f,&p->q1,t);
+ emit(f,",1\n");
+ }
+ }
+ if(jmp&&!need_return) ret="";
+ if(!zmeqto(l2zm(0L),p->q2.val.vmax)){
+ notpopped+=zm2l(p->q2.val.vmax);
+ dontpop-=zm2l(p->q2.val.vmax);
+ if(!(g_flags[2]&USEDFLAG)&&stackoffset==-notpopped){
+ /* Entfernen der Parameter verzoegern */
+ }else{
+ emit(f,"\tadd\t%ld,%s\n",zm2l(p->q2.val.vmax),regnames[sp]);
+ pop(zm2l(p->q2.val.vmax));
+ notpopped-=zm2l(p->q2.val.vmax);cc=0;
+ }
+ }
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax);
+
+ if(c==ASSIGN||c==PUSH){
+ long sz=zm2l(p->q2.val.vmax);
+ int qreg,zreg,creg,i;
+ if(sz==1){
+ load_op(f,&p->q1,t,t1);
+ if(c==ASSIGN){
+ load_op(f,&p->z,t,t2);
+ move(f,&p->q1,0,&p->z,0,t);
+ cc=&p->z;cc_t=t;
+ }else{
+ emit(f,"\tmove\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,",@--%s\n",regnames[sp]);
+ push(zm2l(p->z.val.vmax));
+ cc=&p->q1;cc_t=t;
+ }
+ continue;
+ }else if(ISLWORD(t)&&(isreg(q1)||isreg(z)||(p->q1.flags&(KONST|DREFOBJ))==KONST)){
+ if(c==ASSIGN){
+ move(f,&p->q1,0,&p->z,0,t);
+ }else{
+ load_op(f,&p->q1,t,t1);
+
+ if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ))
+ emit(f,"\tadd\t2,%s\n",regnames[p->q1.reg]);
+
+ emit(f,"\tmove\t");
+ emit_hword(f,&p->q1,t,"@--%s");
+ emit(f,",@--%s\n",regnames[sp]);
+ emit(f,"\tmove\t");
+ emit_lword(f,&p->q1,t,"@--%s");
+ emit(f,",@--%s\n",regnames[sp]);
+ push(2);
+ }
+ cc=0;
+ continue;
+ }else{
+ static char cpstr[64];
+ cc=0;
+ load_op(f,&p->q1,t,t1);
+ if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&scratchreg(p->q1.reg,p)){
+ qreg=p->q1.reg;
+ }else{
+ if(!(p->q1.flags®))
+ ierror(0);
+ qreg=t1;
+ move(f,0,p->q1.reg,0,qreg,INT);
+ }
+ if(c==ASSIGN){
+ load_op(f,&p->z,t,t2);
+ if((p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&scratchreg(p->z.reg,p)){
+ zreg=p->z.reg;
+ }else{
+ if(!(p->z.flags®))
+ ierror(0);
+ if(qreg==t1) zreg=t2; else zreg=t1;
+ move(f,0,p->z.reg,0,zreg,INT);
+ }
+ sprintf(cpstr,"\tmove\t@%s++,@%s++\n",regnames[qreg],regnames[zreg]);
+ }else{
+ zreg=sp;
+ emit(f,"\tadd\t%ld,%s\n",sz,regnames[qreg]);
+ sprintf(cpstr,"\tmove\t@--%s,@--%s\n",regnames[qreg],regnames[zreg]);
+ push(zm2l(p->q2.val.vmax));
+ }
+ if(sz<=9){
+ for(i=0;i<sz;i++)
+ emit(f,cpstr);
+ }else{
+ int cntpushed=0;
+ if(zreg!=t2)
+ creg=t2;
+ else{
+ creg=get_reg(f,p);
+ if(c==PUSH) ierror(0);
+ creg=r8;
+ emit(f,"\tmove\t%s,@--%s\n",regnames[creg],regnames[sp]);
+ cntpushed=1;
+ }
+ emit(f,"\tmove\t%ld,%s\n",sz/4,regnames[creg]);
+ emit(f,"%s%d:\n",labprefix,++label);
+ emit(f,cpstr);
+ emit(f,cpstr);
+ emit(f,cpstr);
+ emit(f,cpstr);
+ emit(f,"\tsub\t1,%s\n",regnames[creg]);
+ emit(f,"\trbra\t%s%d,!z\n",labprefix,label);
+ for(i=0;i<sz%4;i++)
+ emit(f,cpstr);
+ if(cntpushed)
+ emit(f,"\tmove\t@%s++,%s\n",regnames[sp],regnames[creg]);
+ }
+ continue;
+ }
+
+ }
+ ierror(0);
+ }
+ if(c==ADDRESS){
+ reg=0;
+ if(0/*reg_pair(reg,&rp)*/){
+ ierror(0);
+ emit(f,"\tmov\t%s,%s\n",regnames[rp.r1],regnames[sp]);
+ emit(f,"\tmov\t%s,#0\n",regnames[rp.r2]);
+ if(voff(&p->q1))
+ emit(f,"\tadd\t%s,#%ld\n",regnames[rp.r1],voff(&p->q1)&0xffff);
+ }else{
+ if(isreg(z))
+ reg=p->z.reg;
+ else{
+ load_op(f,&p->z,t,t2);
+ }
+ if(voff(&p->q1)){
+ if(!reg) reg=t1;
+ emit(f,"\tmove\t%s,%s\n",regnames[sp],regnames[reg]);
+ emit(f,"\tadd\t%ld,%s\n",voff(&p->q1),regnames[reg]);
+ }else
+ reg=sp;
+ move(f,0,reg,&p->z,0,ztyp(p));
+ }
+ cc=&p->z;cc_t=ztyp(p);
+ continue;
+ }
+
+ if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==COMPARE||c==ADDI2P||c==SUBIFP){
+ char *s;
+
+ if(c==MULT||c==DIV||c==MOD){
+ int code;
+ load_op(f,&p->q1,t,t1);
+ emit(f,"\tmove\t%ld,%s\n",(long)0xff1b,regnames[t2]);
+ emit(f,"\tmove\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,",@%s++\n",regnames[t2]);
+ load_op(f,&p->q2,t,t1);
+ emit(f,"\tmove\t");
+ emit_obj(f,&p->q2,t);
+ emit(f,",@%s++\n",regnames[t2]);
+ emit(f,"\tmove\t%ld,%s\n",(long)0xff1f,regnames[t1]);
+ if(c==MULT) code=0; else code=2;
+ if(!(t&UNSIGNED)) code++;
+ emit(f,"\tmove\t%d,@%s\n",code,regnames[t1]);
+ if(c==MOD)
+ emit(f,"\tmove\t%ld,%s\n",(long)0xff1e,regnames[t2]);
+ load_op(f,&p->z,t,t1);
+ emit(f,"\tmove\t@%s,",regnames[t2]);
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ cc=&p->z;cc_t=t;
+ continue;
+ }
+
+ if(c==LSHIFT&&isconst(q2)&&isreg(q1)){
+ eval_const(&p->q2.val,INT);
+ if(zmeqto(vmax,l2zm(1L))){
+ p->code=c=ADD;
+ p->q2=p->q1;
+ }
+ }
+
+ if(compare_objects(&p->q2,&p->z)){
+ if(!compare_objects(&p->q1,&p->z)){
+ if(c==LSHIFT||c==RSHIFT){
+ reg=get_reg(f,p);
+ if(reg){
+ move(f,&p->q2,0,0,reg,q2typ(p));
+ p->q2.flags=REG;
+ p->q2.reg=reg;
+ }else{
+ emit(f,"\tmove\t");
+ emit_obj(f,&p->q2,q2typ(p));
+ emit(f,",@--%s\n",regnames[sp]);
+ p->q2.flags=REG|DREFOBJ;
+ p->q2.reg=sp;
+ p->q2.am=mymalloc(sizeof(*p->q2.am));
+ p->q2.am->flags=POST_INC;
+ p->q2.am->base=sp;
+ }
+ }else if(c==SUB||c==SUBPFP||c==SUBIFP){
+ /* TODO: check pointer sizes subifp/subpfp */
+ if(ISLWORD(t)){
+ if(isreg(z)){
+ if(!reg_pair(p->z.reg,&rp)) ierror(0);
+ emit(f,"\tnot\t%s,%s\n",regnames[rp.r1],regnames[rp.r1]);
+ emit(f,"\tnot\t%s,%s\n",regnames[rp.r2],regnames[rp.r2]);
+ emit(f,"\tadd\t1,%s\n",regnames[rp.r1]);
+ emit(f,"\taddc\t0,%s\n",regnames[rp.r2]);
+ p->q2=p->q1;
+ p->q1=p->z;
+ p->code=c=ADD;
+ }else
+ ierror(0);
+ }else{
+ load_op(f,&p->z,t,t1);
+ emit(f,"\tnot\t");
+ emit_obj(f,&p->z,t);
+ emit(f,",");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"\tadd\t1,");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ load_op(f,&p->q1,t,t2);
+ emit(f,"\tadd\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,",");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ cc=&p->z;cc_t=t;
+ continue;
+ }
+ }else{
+ struct obj m;
+ m=p->q1;p->q1=p->q2;p->q2=m;
+ }
+ }
+ }
+
+ if(c>=OR&&c<=AND){
+ s=logicals[c-OR];
+ }else{
+ if(c==ADDI2P)
+ s=arithmetics[ADD-LSHIFT];
+ else if(c==SUBIFP)
+ s=arithmetics[SUB-LSHIFT];
+ else
+ s=arithmetics[c-LSHIFT];
+ }
+
+ if(c==COMPARE){
+ lastcomp=t;
+ load_op(f,&p->q1,t,t1);
+ load_op(f,&p->q2,t,t2);
+
+ if(ISLWORD(t)){
+ if((p->q1.flags&DREFOBJ)&&p->q1.reg!=t1){
+ emit(f,"\tmove\t%s,%s\n",regnames[p->q1.reg],regnames[t1]);
+ p->q1.reg=t1;
+ }
+ if((p->q2.flags&DREFOBJ)&&p->q2.reg!=t2){
+ emit(f,"\tmove\t%s,%s\n",regnames[p->q2.reg],regnames[t2]);
+ p->q2.reg=t2;
+ }
+ p2=p->next;
+ while(p2&&p2->code==FREEREG) p2=p2->next;
+ if(!p2||p2->code<BEQ||p2->code>BGT) ierror(0);
+ c=p2->code;
+ if(c==BEQ||c==BNE){
+ emit(f,"\tcmp\t",s);
+ emit_lword(f,&p->q1,t,"@%s++");
+ emit(f,",");
+ emit_lword(f,&p->q2,t,"@%s++");
+ emit(f,"\n");
+ if(c==BEQ)
+ emit(f,"\trbra\t%s%d,!z\n",labprefix,elab=++label);
+ else
+ emit(f,"\trbra\t%s%d,!z\n",labprefix,p2->typf);
+ emit(f,"\tcmp\t",s);
+ emit_hword(f,&p->q1,t,"@%s++");
+ emit(f,",");
+ emit_hword(f,&p->q2,t,"@%s++");
+ emit(f,"\n");
+ emit(f,"\trbra\t%s%d,%s\n",labprefix,p2->typf,ccs[c-BEQ]);
+ }else{
+ elab=++label;
+ if(p->q1.flags&DREFOBJ) emit(f,"\tadd\t1,%s\n",regnames[p->q1.reg]);
+ if(p->q2.flags&DREFOBJ) emit(f,"\tadd\t1,%s\n",regnames[p->q2.reg]);
+ emit(f,"\tcmp\t",s);
+ emit_hword(f,&p->q2,t,"@%s");
+ emit(f,",");
+ emit_hword(f,&p->q1,t,"@%s");
+ emit(f,"\n");
+ emit(f,"\trbra\t%s%d,%s\n",labprefix,c==BLT?p2->typf:elab,(t&UNSIGNED)?ccu[BLT-BEQ]:ccs[BLT-BEQ]);
+ /* unfortunately flags are overwritten... */
+ emit(f,"\tcmp\t",s);
+ emit_hword(f,&p->q2,t,"@%s");
+ emit(f,",");
+ emit_hword(f,&p->q1,t,"@%s");
+ emit(f,"\n");
+ emit(f,"\trbra\t%s%d,!z\n",labprefix,c==BLT?elab:p2->typf);
+ if(p->q1.flags&DREFOBJ) emit(f,"\tsub\t1,%s\n",regnames[p->q1.reg]);
+ if(p->q2.flags&DREFOBJ) emit(f,"\tsub\t1,%s\n",regnames[p->q2.reg]);
+ emit(f,"\tcmp\t",s);
+ emit_lword(f,&p->q2,t,"@%s");
+ emit(f,",");
+ emit_lword(f,&p->q1,t,"@%s");
+ emit(f,"\n");
+ emit(f,"\trbra\t%s%d,%s\n",labprefix,p2->typf,ccu[c-BEQ]);
+ }
+ cc=0;
+#if 0
+ /* last branch done in branch IC */
+ lastcomp=UNSIGNED|INT;
+#else
+ if(c!=BNE)
+ emit(f,"%s%d:\n",labprefix,elab);
+ p2->code=NOP;
+#endif
+ continue;
+ }else{
+ emit(f,"\tcmp\t",s);
+ emit_obj(f,&p->q2,t);
+ emit(f,",");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ cc=0;
+ continue;
+ }
+
+
+ if(!compare_objects(&p->q1,&p->z)){
+ load_op(f,&p->q1,t,t1);
+ load_op(f,&p->z,t,t2);
+ if((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&isreg(z)&&p->q2.reg==p->z.reg){
+ move(f,0,p->q2.reg,0,t2,NPOINTER);
+ p->q2.reg=t2;
+ }
+ move(f,&p->q1,0,&p->z,0,t);
+ /* cleanup postinc if necessary (not done by cleanup_lword */
+ if(p->z.reg==t2&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ISLWORD(t))
+ emit(f,"\tsub\t2,%s\n",regnames[t2]);
+ }else
+ load_op(f,&p->z,t,t2);
+ load_op(f,&p->q2,t,t1);
+
+ if(ISLWORD(t)){
+
+ emit(f,"\t%s\t",s);
+ emit_lword(f,&p->q2,t,"@%s++");
+ emit(f,",");
+ emit_lword(f,&p->z,t,"@%s++");
+ emit(f,"\n");
+ emit(f,"\t%s%s\t",s,!strcmp(s,"add")||!strcmp(s,"sub")?"c":"");
+ emit_hword(f,&p->q2,t,"@%s++");
+ emit(f,",");
+ emit_hword(f,&p->z,t,"@%s++");
+ emit(f,"\n");
+ cleanup_lword(f,&p->q2);
+ cleanup_lword(f,&p->z);
+ cc=0;
+
+ }else{
+
+ /* TODO: try to eliminate */
+ if(c==LSHIFT){
+ emit(f,"\tcmp\t%s,%s\n",regnames[sp],regnames[sp]);
+ }else if(c==RSHIFT){
+ if(t&UNSIGNED){
+ emit(f,"\tor\t%s,%s\n",regnames[sp],regnames[sp]);
+ }else{
+ emit(f,"\tshl\t1,");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"\tshr\t1,");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ }
+ }
+ emit(f,"\t%s\t",s);
+ emit_obj(f,&p->q2,t);
+ emit(f,",");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ cc=&p->z;cc_t=t;
+
+ }
+ if(ISLWORD(t)) cc=0;
+
+ continue;
+ }
+ ierror(0);
+ }
+ if(notpopped){
+ emit(f,"\tadd\t%ld,%s\n",notpopped,regnames[sp]);
+ pop(notpopped);notpopped=0;
+ }
+ function_bottom(f,v,loff);
+}
+
+int shortcut(int c,int t)
+{
+ if(c==COMPARE||c==AND||c==OR||c==XOR) return 1;
+ if(c==ADD||c==SUB) return 1;
+ return 0;
+}
+
+void cleanup_cg(FILE *f)
+{
+ struct fpconstlist *p;
+ unsigned char *ip;
+ if(f&&stack_check){
+ emit(f,"\t.global\t%s__stack_check\n",idprefix);
+ }
+ while(p=firstfpc){
+ if(f){
+ new_section(f,NDATA);
+ emit(f,"%s%d:\n\t%s\t",labprefix,p->label,dct[SHORT]);
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x,0x%02x%02x",ip[1],ip[0],ip[3],ip[2]);
+ if((p->typ&NQ)==DOUBLE||(p->typ&NQ)==LDOUBLE){
+ emit(f,",0x%02x%02x,0x%02x%02x",ip[5],ip[4],ip[7],ip[6]);
+ }
+ emit(f,"\n");
+ }
+ firstfpc=p->next;
+ free(p);
+ }
+}
+
+int reg_parm(struct reg_handle *p,struct Typ *t,int mode,struct Typ *fkt)
+{
+ int f=t->flags&NQ;
+ if(!ISSCALAR(f)) return 0;
+ if(p->gpr>2||mode) return 0;
+ if(f==LLONG||f==DOUBLE||f==LDOUBLE)
+ return 0;
+ else if(f==LONG||f==FLOAT||f==FPOINTER||f==HPOINTER){
+ if(p->gpr==0) {p->gpr=2;return r8r9;}
+ return 0;
+ }else
+ return r8+p->gpr++;
+}
+
+void insert_const(union atyps *p,int t)
+/* Traegt Konstante in entprechendes Feld ein. */
+{
+ if(!p) ierror(0);
+/* *p = (union atyps) 0 ; /* rfi: clear unused bits */
+ t&=NU;
+ if(t==CHAR) {p->vchar=vchar;return;}
+ if(t==SHORT) {p->vshort=vshort;return;}
+ if(t==INT) {p->vint=vint;return;}
+ if(t==LONG) {p->vlong=vlong;return;}
+ if(t==LLONG) {p->vllong=vllong;return;}
+ if(t==MAXINT) {p->vmax=vmax;return;}
+ if(t==(UNSIGNED|BIT)) {if(zumeqto(zuc2zum(vuchar),ul2zum(0UL))) p->vuchar=zum2zuc(ul2zum(0UL)); else p->vuchar=zum2zuc(ul2zum(1UL));return;}
+ if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+ if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+ if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+ if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+ if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+ if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+ if(t==FLOAT) {p->vfloat=vfloat;return;}
+ if(t==DOUBLE) {p->vdouble=vdouble;return;}
+ if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+ if(t==NPOINTER) {p->vuint=vuint;return;}
+ if(t==FPOINTER||t==HPOINTER) {p->vulong=vulong;return;}
+}
+void eval_const(union atyps *p,int t)
+/* Weist bestimmten globalen Variablen Wert einer CEXPR zu. */
+{
+ int f=t&NQ;
+ if(!p) ierror(0);
+ if(f==MAXINT||(f>=BIT&&f<=LLONG)){
+ if(!(t&UNSIGNED)){
+ if(f==CHAR) vmax=zc2zm(p->vchar);
+ else if(f==SHORT)vmax=zs2zm(p->vshort);
+ else if(f==INT) vmax=zi2zm(p->vint);
+ else if(f==LONG) vmax=zl2zm(p->vlong);
+ else if(f==LLONG) vmax=zll2zm(p->vllong);
+ else if(f==MAXINT) vmax=p->vmax;
+ else ierror(0);
+ vumax=zm2zum(vmax);
+ vldouble=zm2zld(vmax);
+ }else{
+ if(f==CHAR) vumax=zuc2zum(p->vuchar);
+ else if(f==SHORT)vumax=zus2zum(p->vushort);
+ else if(f==INT) vumax=zui2zum(p->vuint);
+ else if(f==LONG) vumax=zul2zum(p->vulong);
+ else if(f==LLONG) vumax=zull2zum(p->vullong);
+ else if(f==MAXINT) vumax=p->vumax;
+ else ierror(0);
+ vmax=zum2zm(vumax);
+ vldouble=zum2zld(vumax);
+ }
+ }else{
+ if(ISPOINTER(f)){
+ if(f==NPOINTER)
+ vumax=zui2zum(p->vuint);
+ else
+ vumax=zul2zum(p->vulong);
+ vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+ }else{
+ if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+ else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+ else vldouble=p->vldouble;
+ vmax=zld2zm(vldouble);
+ vumax=zld2zum(vldouble);
+ }
+ }
+ vfloat=zld2zf(vldouble);
+ vdouble=zld2zd(vldouble);
+ vuchar=zum2zuc(vumax);
+ vushort=zum2zus(vumax);
+ vuint=zum2zui(vumax);
+ vulong=zum2zul(vumax);
+ vullong=zum2zull(vumax);
+ vchar=zm2zc(vmax);
+ vshort=zm2zs(vmax);
+ vint=zm2zi(vmax);
+ vlong=zm2zl(vmax);
+ vllong=zm2zll(vmax);
+}
+void printval(FILE *f,union atyps *p,int t)
+/* Gibt atyps aus. */
+{
+ t&=NU;
+ if(t==BIT){fprintf(f,"B");vmax=zc2zm(p->vchar);fprintf(f,"%d",!zmeqto(vmax,l2zm(0L)));}
+ if(t==(UNSIGNED|BIT)){fprintf(f,"UB");vumax=zuc2zum(p->vuchar);fprintf(f,"%d",!zumeqto(vmax,ul2zum(0UL)));}
+ if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+ if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+ if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+ if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+ if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+ if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+ if(t==(UNSIGNED|INT)||t==NPOINTER){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+ if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+ if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+ if(t==MAXINT) printzm(f,p->vmax);
+ if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax);
+}
+void emitval(FILE *f,union atyps *p,int t)
+/* Gibt atyps aus. */
+{
+ t&=NU;
+ if(t==BIT){vmax=zc2zm(p->vchar);emit(f,"%d",!zmeqto(vmax,l2zm(0L)));}
+ if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);emit(f,"%d",!zumeqto(vumax,ul2zum(0UL)));}
+ if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+ if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+ if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+ if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+ if(t==LDOUBLE){emitzld(f,p->vldouble);}
+ if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+ if(t==(UNSIGNED|INT)||t==NPOINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+ if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+ if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+ if(t==MAXINT) emitzm(f,p->vmax);
+ if(t==(UNSIGNED|MAXINT)) emitzum(f,p->vumax);
+}
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+ char *attr;
+ while(p){
+ if(ISPOINTER(p->flags)){
+ p->flags=((p->flags&~NU)|POINTER_TYPE(p->next));
+ if(attr=p->next->attr){
+ if(strstr(attr,STR_NEAR))
+ p->flags=((p->flags&~NU)|NPOINTER);
+ if(strstr(attr,STR_FAR))
+ p->flags=((p->flags&~NU)|FPOINTER);
+ if(strstr(attr,STR_HUGE))
+ p->flags=((p->flags&~NU)|HPOINTER);
+ }
+ }
+ if(ISINT(p->flags)&&(attr=p->attr)&&strstr(attr,"bit"))
+ p->flags=((p->flags&~NU)|BIT);
+ p=p->next;
+ }
+}
+
+void init_db(FILE *f)
+{
+}
+
+void cleanup_db(FILE *f)
+{
+}
+
+char *use_libcall(int c,int t,int t2)
+{
+ static char fname[16];
+ char *ret=0,*tt;
+
+ if(c==COMPARE){
+ if((t&NQ)==LLONG||ISFLOAT(t)){
+ sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*16);
+ ret=fname;
+ }
+ }else{
+ t&=NU;
+ t2&=NU;
+ if(t==LDOUBLE) t=DOUBLE;
+ if(t2==LDOUBLE) t2=DOUBLE;
+ if(c==CONVERT){
+ if(t==t2) return 0;
+ if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+ if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+
+ if(ISFLOAT(t)){
+ sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*16,(t==FLOAT)?32:64);
+ ret=fname;
+ }
+ if(ISFLOAT(t2)){
+ sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*16);
+ ret=fname;
+ }
+ if((t&NQ)==LLONG||(t2&NQ)==LLONG){
+ sprintf(fname,"__%cint%ldto%cint%ld",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*16,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*16);
+ ret=fname;
+ }
+ }
+ if(ISINT(t)&&ISLWORD(t)){
+ if(c==MINUS||c==KOMPLEMENT||c==ADD||c==SUB||c==OR||c==AND||c==XOR)
+ return 0;
+ }
+ if((t&NQ)==LONG||(t&NQ)==LLONG||ISFLOAT(t)||(SOFTMUL&&(c==MULT||c==DIV||c==MOD))){
+ if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+ if(c!=DIV&&c!=MOD&&c!=RSHIFT&&c!=COMPARE)
+ t&=~UNSIGNED;
+ sprintf(fname,"__%s%s%s%ld",ename[c],(t&UNSIGNED)?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*16);
+ ret=fname;
+ }
+ }
+ }
+
+
+ return ret;
+}
diff --git a/machines/qnice/machine.dt b/machines/qnice/machine.dt
new file mode 100755
index 0000000..fa60647
--- /dev/null
+++ b/machines/qnice/machine.dt
@@ -0,0 +1,16 @@
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEELE
+S64BIEEELE
+S64BIEEELE
+S16BULE S16BUBE
+
+
diff --git a/machines/qnice/machine.h b/machines/qnice/machine.h
new file mode 100755
index 0000000..b9795a3
--- /dev/null
+++ b/machines/qnice/machine.h
@@ -0,0 +1,185 @@
+/* Example of a code-generator for qnice cpu.*/
+
+#include "dt.h"
+
+/* We have extended types! What we have to do to support them: */
+/* - #define HAVE_EXT_TYPES
+ - #undef all standard types
+ - #define all standard types plus new types
+ - write eval_const and insert_const
+ - write typedefs for zmax and zumax
+ - write typname[]
+ - write conv_typ()
+ - optionally #define ISPOINTER, ISARITH, ISINT etc.
+ - optionally #define HAVE_TGT_PRINTVAL and write printval
+ - optionally #define POINTER_TYPE
+ - optionally #define HAVE_TGT_FALIGN and write falign
+ - optionally #define HAVE_TGT_SZOF and write szof
+ - optionally add functions for attribute-handling
+*/
+#define HAVE_EXT_TYPES 1
+
+#define HAVE_TGT_PRINTVAL
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef BOOL
+#undef MAXINT
+#undef MAX_TYPE
+
+#define BIT 1
+#define CHAR 2
+#define SHORT 3
+#define INT 4
+#define LONG 5
+#define LLONG 6
+#define FLOAT 7
+#define DOUBLE 8
+#define LDOUBLE 9
+#define VOID 10
+#define NPOINTER 11
+#define FPOINTER 12
+#define HPOINTER 13
+#define ARRAY 14
+#define STRUCT 15
+#define UNION 16
+#define ENUM 17
+#define FUNKT 18
+#define BOOL 19
+
+#define MAXINT 20
+
+#define MAX_TYPE MAXINT
+
+#define POINTER_TYPE(x) pointer_type(x)
+extern int pointer_type();
+#define ISPOINTER(x) ((x&NQ)>=NPOINTER&&(x&NQ)<=HPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=BIT&&(x&NQ)<=HPOINTER)
+#define ISINT(x) ((x&NQ)>=BIT&&(x&NQ)<=LLONG)
+#define PTRDIFF_T(x) ((x)==HPOINTER?LONG:INT)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+ zchar vchar;
+ zuchar vuchar;
+ zshort vshort;
+ zushort vushort;
+ zint vint;
+ zuint vuint;
+ zlong vlong;
+ zulong vulong;
+ zllong vllong;
+ zullong vullong;
+ zmax vmax;
+ zumax vumax;
+ zfloat vfloat;
+ zdouble vdouble;
+ zldouble vldouble;
+};
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+struct AddressingMode{
+ int flags;
+ int base;
+};
+
+/* This type will be added to every IC. Can be used by the cg. */
+#define HAVE_EXT_IC 0
+struct ext_ic {
+ int flags;
+ int r;
+ long offset;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR 22
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 20
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P CHAR
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 0
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 1
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+#define HAVE_REGPARMS 1
+
+struct reg_handle {
+ int gpr;
+};
+
+/* We use unsigned int as size_t rather than unsigned long which */
+/* is the default setting. */
+#define HAVE_INT_SIZET 1
+
+/* We have register pairs. */
+#define HAVE_REGPAIRS 1
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+#define HAVE_TARGET_RALLOC 1
+#define cost_load_reg(r,v) 4
+#define cost_save_reg(r,v) 4
+#define cost_move_reg(i,j) 2
+#define cost_pushpop_reg(r) 2
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/* We have asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES 1
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+#define HAVE_WANTBNE 1
+
+#define HAVE_POF2OPT 1
diff --git a/machines/qnice/sysdef.h b/machines/qnice/sysdef.h
new file mode 100644
index 0000000..bdc733e
--- /dev/null
+++ b/machines/qnice/sysdef.h
@@ -0,0 +1,461 @@
+//;
+//; sysdef.asm: This file contains definitions to simplify assembler programming
+//; and for accessing the various hardware registers via MMIO
+//;
+//
+//***************************************************************************************
+//* Assembler macros which make life much easier:
+//***************************************************************************************
+//
+
+
+//
+// Some register short names:
+//
+
+//
+//***************************************************************************************
+//* IO-page addresses: Default: 8 registers per block
+//***************************************************************************************
+//
+#define IO_AREA_START 0xFF00
+//
+//---------------------------------------------------------------------------------------
+// Block FF00: FUNDAMENTAL IO
+//---------------------------------------------------------------------------------------
+//
+// Switch-register:
+//
+#define IO_SWITCH_REG 0xFF00 // 16 binary keys
+//
+// Registers for TIL-display:
+//
+#define IO_TIL_DISPLAY 0xFF01 // Address of TIL-display
+#define IO_TIL_MASK 0xFF02 // Mask register of TIL display
+//
+// USB-keyboard-registers:
+//
+#define IO_KBD_STATE 0xFF04 // Status register of USB keyboard
+// Bit 0 (read only): New ASCII character avaiable for reading
+// (bits 7 downto 0 of Read register)
+// Bit 1 (read only): New special key available for reading
+// (bits 15 downto 8 of Read register)
+// Bits 2..4 (read/write): Locales: 000 = US English keyboard layout,
+// 001 = German layout, others: reserved for more locales
+// Bits 5..7 (read only): Modifiers: 5 = shift, 6 = alt, 7 = ctrl
+// Only valid, when bits 0 and/or 1 are '1'
+//
+#define IO_KBD_DATA 0xFF05 // Data register of USB keyboard
+// Contains the ASCII character in bits 7 downto 0 or the special key code
+// in 15 downto 8. The "or" is meant exclusive, i.e. it cannot happen that
+// one transmission contains an ASCII character PLUS a special character.
+//
+//---------------------------------------------------------------------------------------
+// Block FF08: SYSTEM COUNTERS
+//---------------------------------------------------------------------------------------
+//
+// CYCLE-COUNT-registers
+//
+#define IO_CYC_LO 0xFF08 // low word of 48-bit counter
+#define IO_CYC_MID 0xFF09 // middle word of 48-bit counter
+#define IO_CYC_HI 0xFF0A // high word of 48-bit counter
+#define IO_CYC_STATE 0xFF0B // status register
+// Bit 0 (write only): Reset counter to zero and start counting, i.e.
+// bit 1 is automatically set to 1 when resetting
+// Bit 1 (read/write): Start/stop counter
+//
+// INSTRUCTION-COUNT-registers
+//
+#define IO_INS_LO 0xFF0C // low word of 48-bit counter
+#define IO_INS_MID 0xFF0D // middle word of 48-bit counter
+#define IO_INS_HI 0xFF0E // high word of 48-bit counter
+#define IO_INS_STATE 0xFF0F // status register
+// Bit 0 (write only): Reset counter to zero and start counting, i.e.
+// bit 1 is automatically set to 1 when resetting
+// Bit 1 (read/write): Start/stop counter
+//
+//---------------------------------------------------------------------------------------
+// Block FF10: UART
+//---------------------------------------------------------------------------------------
+//
+// QNICE-FPGA supports: IO_UART_SRA, IO_UART_RHRA and IO_UART_THRA
+// The other registers are mentioned for completeness to map real hardware (16550)
+//
+#define IO_UART_BASE_ADDRESS 0xFF10
+#define IO_UART_MR1A 0xFF10 // n/a
+#define IO_UART_MR1B 0xFF10 // n/a
+#define IO_UART_SRA 0xFF11 // Status register (relative to base address)
+#define IO_UART_RHRA 0xFF12 // Receiving register (relative to base address)
+#define IO_UART_THRA 0xFF13 // Transmitting register (relative to base address)
+//
+//---------------------------------------------------------------------------------------
+// Block FF18: EAE
+//---------------------------------------------------------------------------------------
+//
+// EAE (Extended Arithmetic Element) registers:
+//
+#define IO_EAE_OPERAND_0 0xFF18
+#define IO_EAE_OPERAND_1 0xFF19
+#define IO_EAE_RESULT_LO 0xFF1A
+#define IO_EAE_RESULT_HI 0xFF1B
+#define IO_EAE_CSR 0xFF1C // Command and Status Register
+//
+// EAE-Opcodes (CSR): 0x0000 MULU 32-bit result in LO HI
+// 0x0001 MULS 32-bit result in LO HI
+// 0x0002 DIVU result in LO, modulo in HI
+// 0x0003 DIVS result in LO, modulo in HI
+// Bit 15 of CSR is the busy bit. If it is set, the EAE is still busy crunching numbers.
+//
+//---------------------------------------------------------------------------------------
+// Block FF20: SD CARD
+//---------------------------------------------------------------------------------------
+//
+// SD CARD INTERFACE registers
+//
+#define IO_SD_BASE_ADDRESS 0xFF20
+#define IO_SD_ADDR_LO 0xFF20 // low word of 32bit linear SD card block address
+#define IO_SD_ADDR_HI 0xFF21 // high word of 32bit linear SD card block address
+#define IO_SD_DATA_POS 0xFF22 // "Cursor" to navigate the 512-byte data buffer
+#define IO_SD_DATA 0xFF23 // read/write 1 byte from/to the 512-byte data buffer
+#define IO_SD_ERROR 0xFF24 // error code of last operation (read only)
+#define IO_SD_CSR 0xFF25 // Command and Status Register (write to execute command)
+//
+// SD-Opcodes (CSR): 0x0000 Reset SD card
+// 0x0001 Read 512 bytes from the linear block address
+// 0x0002 Write 512 bytes to the linear block address
+// Bits 0 .. 2 are write-only (reading always returns 0)
+// Bits 13 .. 12 return the card type: 00 = no card / unknown card
+// 01 = SD V1
+// 10 = SD V2
+// 11 = SDHC
+// Bit 14 of the CSR is the error bit: 1, if the last operation failed. In such
+// a case, the error code is in IO_SD_ERROR and
+// you need to reset the controller to go on
+// Bit 15 of the CSR is the busy bit: 1, if current operation is still running
+//
+//---------------------------------------------------------------------------------------
+// Block FF28: TIMER 0 and 1
+//---------------------------------------------------------------------------------------
+//
+// Interrupt timer: There are two timers capable of generating interrupts.
+// Each timer is controlled by three 16 bit registers:
+//
+// IO_TIMER_x_PRE: The 100 kHz timer clock is divided by the value stored in
+// this device register. 100 (which corresponds to 0x0064 in
+// the prescaler register) yields a 1 millisecond pulse which
+// in turn is fed to the actual counter.
+// IO_TIMER_x_CNT: When the number of output pulses from the prescaler circuit
+// equals the number stored in this register, an interrupt will
+// be generated (if the interrupt address is 0x0000, the
+// interrupt will be suppressed).
+// IO_TIMER_x_INT: This register contains the address of the desired interrupt
+// service routine.
+//
+#define IO_TIMER_BASE_ADDRESS 0xFF28
+#define IO_TIMER_0_PRE 0xFF28
+#define IO_TIMER_0_CNT 0xFF29
+#define IO_TIMER_0_INT 0xFF2A
+#define IO_TIMER_1_PRE 0xFF2B
+#define IO_TIMER_1_CNT 0xFF2C
+#define IO_TIMER_1_INT 0xFF2D
+//
+//---------------------------------------------------------------------------------------
+// Block FF30: VGA (double block, 16 registers)
+//---------------------------------------------------------------------------------------
+//
+#define VGA_STATE 0xFF30 // VGA status register
+ // Bits 11-10: Hardware scrolling / offset enable: Bit #10 enables the use
+ // of the offset register #4 (display offset) and bit #11
+ // enables the use of register #5 (read/write offset).
+ // Bit 9: Busy: VGA is currently busy, e.g. clearing the screen,
+ // printing, etc. While busy, commands will be ignored, but
+ // they can still be written into the registers, though
+ // Bit 8: Set bit to clear screen. Read bit to find out, if clear
+ // screen is still active
+ // Bit 7: VGA enable (1 = on; 0: no VGA signal is generated)
+ // Bit 6: Hardware cursor enable
+ // Bit 5: Hardware cursor blink enable
+ // Bit 4: Hardware cursor mode: 1 - small
+ // 0 - large
+ // Bits 2-0: Output color for the whole screen, bits (2, 1, 0) = RGB
+#define VGA_CR_X 0xFF31 // VGA cursor X position
+#define VGA_CR_Y 0xFF32 // VGA cursor Y position
+#define VGA_CHAR 0xFF33 // write: VGA character to be displayed
+ // read: character "under" the cursor
+#define VGA_OFFS_DISPLAY 0xFF34 // Offset in bytes that is used when displaying
+ // the video RAM. Scrolling forward one line
+ // means adding 0x50 to this register.
+ // Only works, if bit #10 in VGA_STATE is set.
+#define VGA_OFFS_RW 0xFF35 // Offset in bytes that is used, when you read
+ // or write to the video RAM using VGA_CHAR.
+ // Works independently from VGA_OFFS_DISPLAY.
+ // Active, when bit #11 in VGA_STATE is set.
+#define VGA_HDMI_H_MIN 0xFF36 // HDMI Data Enable: X: minimum valid column
+#define VGA_HDMI_H_MAX 0xFF37 // HDMI Data Enable: X: maximum valid column
+#define VGA_HDMI_V_MAX 0xFF38 // HDMI Data Enable: Y: maximum row (line)
+//
+//---------------------------------------------------------------------------------------
+// Block FFF0: MEGA65 (double block, 16 registers)
+//---------------------------------------------------------------------------------------
+//
+// HyperRAM
+//
+#define IO_M65HRAM_LO 0xFFF0 // Low word of address (15 downto 0)
+#define IO_M65HRAM_HI 0xFFF1 // High word of address (26 downto 16)
+#define IO_M65HRAM_DATA8 0xFFF2 // HyperRAM native 8-bit data in/out
+#define IO_M65HRAM_DATA16 0xFFF3 // HyperRAM 16-bit data in/out
+
+//
+//***************************************************************************************
+//* Constant definitions
+//***************************************************************************************
+//
+
+// ========== VGA ==========
+
+#define VGA_MAX_X 79 // Max. X-coordinate in decimal!
+#define VGA_MAX_Y 39 // Max. Y-coordinate in decimal!
+#define VGA_MAX_CHARS 3200 // 80 * 40 chars
+#define VGA_CHARS_PER_LINE 80
+
+#define VGA_EN_HW_CURSOR 0x0040 // Show hardware cursor
+#define VGA_EN_HW_SCRL 0x0C00 // Hardware scrolling enable
+#define VGA_CLR_SCRN 0x0100 // Clear screen
+#define VGA_BUSY 0x0200 // VGA is currently performing a task
+
+#define VGA_COLOR_RED 0x0004
+#define VGA_COLOR_GREEN 0x0002
+#define VGA_COLOR_BLUE 0x0001
+#define VGA_COLOR_WHITE 0x0007
+
+// ========== CYCLE COUNTER ==========
+
+#define CYC_RESET 0x0001 // Reset cycle counter
+#define CYC_RUN 0x0002 // Start/stop counter
+
+// ========== CYCLE COUNTER ==========
+
+#define INS_RESET 0x0001 // Reset instruction counter
+#define INS_RUN 0x0002 // Start/stop counter
+
+// ========== EAE ==========
+
+#define EAE_MULU 0x0000 // Unsigned 16 bit multiplication
+#define EAE_MULS 0x0001 // Signed 16 bit multiplication
+#define EAE_DIVU 0x0002 // Unsigned 16 bit division with remainder
+#define EAE_DIVS 0x0003 // Signed 16 bit division with remainder
+#define EAE_BUSY 0x8000 // Busy flag (1 = operation still running)
+
+// ========== SD CARD ==========
+
+#define SD_CMD_RESET 0x0000 // Reset SD card
+#define SD_CMD_READ 0x0001 // Read 512 bytes from SD to internal buffer
+#define SD_CMD_WRITE 0x0002 // Write 512 bytes from int. buf. to SD
+#define SD_BIT_ERROR 0x4000 // Error flag: 1, if last operation failed
+#define SD_BIT_BUSY 0x8000 // Busy flag: 1, if current op. is still running
+#define SD_TIMEOUT_MID 0x0479 // equals ~75.000.000 cycles, i.e. 1.5sec @ 50 MHz
+
+#define SD_ERR_MASK 0x00FF // AND mask for errors: HI byte = state machine info, so mask it for error checks
+#define SD_ERR_R1_ERROR 0x0001 // SD Card R1 error (R1 bit 6-0)
+#define SD_ERR_CRC_OR_TIMEOUT 0x0002 // Read CRC error or Write Timeout error
+#define SD_ERR_RESPONSE_TOKEN 0x0003 // Data Response Token error (Token bit 3)
+#define SD_ERR_ERROR_TOKEN 0x0004 // Data Error Token error (Token bit 3-0)
+#define SD_ERR_WRITE_PROTECT 0x0005 // SD Card Write Protect switch
+#define SD_ERR_CARD_UNUSABLE 0x0006 // Unusable SD card
+#define SD_ERR_NO_CARD 0x0007 // No SD card (no response from CMD0)
+#define SD_ERR_READ_TIMEOUT 0x0008 // Timeout while trying to receive the read start token "FE"
+#define SD_ERR_TIMEOUT 0xEEFF // General timeout
+
+#define SD_CT_SD_V1 0x0001 // Card type: SD Version 1
+#define SD_CT_SD_V2 0x0002 // Card type: SD Version 2
+#define SD_CT_SDHC 0x0003 // Card type: SDHC (or SDXC)
+
+// ========== FAT32 =============
+
+// FAT32 ERROR CODES
+
+#define FAT32_ERR_MBR 0xEE10 // no or illegal Master Boot Record (MBR) found
+#define FAT32_ERR_PARTITION_NO 0xEE11 // the partition number needs to be in the range 1 .. 4
+#define FAT32_ERR_PARTTBL 0xEE12 // no or illegal partition table entry found (e.g. no FAT32 partition)
+#define FAT32_ERR_NOTIMPL 0xEE13 // functionality is not implemented
+#define FAT32_ERR_SIZE 0xEE14 // partition size or volume size too large (see doc/constraints.txt)
+#define FAT32_ERR_NOFAT32 0xEE15 // illegal volume id (either not 512 bytes per sector, or not 2 FATs or wrong magic)
+#define FAT32_ERR_ILLEGAL_SIC 0xEE16 // trying to read/write a sector within a cluster that is out of range
+#define FAT32_ERR_ILLEGAL_CLUS 0xEE17 // trying to access an illegal cluster number
+#define FAT32_ERR_CORRUPT_DH 0xEE18 // corrupt directory handle (e.g. because current to-be-read offs > sector size)
+#define FAT32_ERR_DIRNOTFOUND 0xEE19 // directory not found (illegal path name passed to change directory command)
+#define FAT32_ERR_FILENOTFOUND 0xEE20 // file not found
+#define FAT23_ERR_SEEKTOOLARGE 0xEE21 // seek position > file size
+
+// FAT32 STATUS CODES
+
+#define FAT32_EOF 0xEEEE // end of file reached
+
+// LAYOUT OF THE MOUNT DATA STRUCTURE (DEVICE HANDLE)
+
+#define FAT32_DEV_RESET 0x0000 // pointer to device reset function
+#define FAT32_DEV_BLOCK_READ 0x0001 // pointer to 512-byte block read function
+#define FAT32_DEV_BLOCK_WRITE 0x0002 // pointer to 512-byte block write function
+#define FAT32_DEV_BYTE_READ 0x0003 // pointer to 1-byte read function (within block buffer)
+#define FAT32_DEV_BYTE_WRITE 0x0004 // pointer to 1-byte write function (within block buffer)
+#define FAT32_DEV_PARTITION 0x0005 // number of partition to be mounted
+#define FAT32_DEV_FS_LO 0x0006 // file system start address (LBA): low word
+#define FAT32_DEV_FS_HI 0x0007 // file system start address (LBA): high word
+#define FAT32_DEV_FAT_LO 0x0008 // fat start address (LBA): low word
+#define FAT32_DEV_FAT_HI 0x0009 // fat start address (LBA): high word
+#define FAT32_DEV_CLUSTER_LO 0x000A // cluster start address (LBA): low word
+#define FAT32_DEV_CLUSTER_HI 0x000B // cluster start address (LBA): high word
+#define FAT32_DEV_SECT_PER_CLUS 0x000C // sectors per cluster
+#define FAT32_DEV_RD_1STCLUS_LO 0x000D // root directory first cluster: low word
+#define FAT32_DEV_RD_1STCLUS_HI 0x000E // root directory first cluster: high word
+#define FAT32_DEV_AD_1STCLUS_LO 0x000F // currently active directory first cluster: low word
+#define FAT32_DEV_AD_1STCLUS_HI 0x0010 // currently active directory first cluster: high word
+#define FAT32_DEV_BUFFERED_FDH 0x0011 // FDH which is responsible for the current 512 byte hardware buffer filling
+
+#define FAT32_DEV_STRUCT_SIZE 0x0012 // size (words) of the mount data structure (device handle)
+
+// LAYOUT OF THE FILE HANDLE AND DIRECTORY HANDLE (FDH)
+
+#define FAT32_FDH_DEVICE 0x0000 // pointer to the device handle
+#define FAT32_FDH_CLUSTER_LO 0x0001 // current cluster (low word)
+#define FAT32_FDH_CLUSTER_HI 0x0002 // current cluster (high word)
+#define FAT32_FDH_SECTOR 0x0003 // current sector
+#define FAT32_FDH_INDEX 0x0004 // current byte index within current sector
+#define FAT32_FDH_SIZE_LO 0x0005 // only in case FDH is a file: low word of file size, otherwise undefined
+#define FAT32_FDH_SIZE_HI 0x0006 // only in case FDH is a file: high word of file size, otherwise undefined
+#define FAT32_FDH_READ_LO 0x0007 // only in case FDH is a file: low word of already read amount of bytes
+#define FAT32_FDH_READ_HI 0x0008 // only in case FDH is a file: high word of already read amount of bytes
+
+#define FAT32_FDH_STRUCT_SIZE 0x0009 // size of the directory handle structure
+
+// FILE ATTRIBUTES
+
+#define FAT32_FA_READ_ONLY 0x0001 // read only file
+#define FAT32_FA_HIDDEN 0x0002 // hidden file
+#define FAT32_FA_SYSTEM 0x0004 // system file
+#define FAT32_FA_VOLUME_ID 0x0008 // volume id (name of the volume)
+#define FAT32_FA_DIR 0x0010 // directory
+#define FAT32_FA_ARCHIVE 0x0020 // archive flag
+
+#define FAT32_FA_DEFAULT 0x0035 // browse for non hidden files and directories but not for the volume id
+#define FAT32_FA_ALL 0x0037 // browse for all files, but not for the volume id
+
+// LAYOUT OF THE DIRECTORY ENTRY STRUCTURE
+
+#define FAT32_DE_NAME 0x0000 // volume, file or directory name, zero terminated (max 256 characters)
+#define FAT32_DE_ATTRIB 0x0101 // file attributes (read-only, hidden, system, volume id, directory, archive)
+#define FAT32_DE_SIZE_LO 0x0102 // file size: low word
+#define FAT32_DE_SIZE_HI 0x0103 // file size: high word
+#define FAT32_DE_YEAR 0x0104 // last file write: year (valid range 1980 .. 2107)
+#define FAT32_DE_MONTH 0x0105 // last file write: month
+#define FAT32_DE_DAY 0x0106 // last file write: day
+#define FAT32_DE_HOUR 0x0107 // last file write: hour
+#define FAT32_DE_MINUTE 0x0108 // last file write: minute
+#define FAT32_DE_SECOND 0x0109 // last file write: second (in 2 second steps, valid range 0 .. 58)
+#define FAT32_DE_CLUS_LO 0x010A // start cluster: low word
+#define FAT32_DE_CLUS_HI 0x010B // start cluster: high word
+
+#define FAT32_DE_STRUCT_SIZE 0x010C // size (words) of the directory entry data structure of the
+
+// DISPLAY FLAGS FOR FILE ENTRY PRETTY PRINTER
+
+#define FAT32_PRINT_SHOW_DIR 0x0001 // show "<DIR>" indicator
+#define FAT32_PRINT_SHOW_ATTRIB 0x0002 // show attributes as "HRSA"
+#define FAT32_PRINT_SHOW_SIZE 0x0004 // show file size
+#define FAT32_PRINT_SHOW_DATE 0x0008 // show file date as YYYY-MM-DD
+#define FAT32_PRINT_SHOW_TIME 0x0010 // show file time as HH:MM
+
+#define FAT32_PRINT_DEFAULT 0x001D // print <DIR> indicator, size, date and time (no attributes)
+#define FAT32_PRINT_ALL 0x001F // print all details
+
+// ========== KEYBOARD ==========
+
+// STATUS REGISTER
+
+#define KBD_NEW_ASCII 0x0001 // new ascii character available
+#define KBD_NEW_SPECIAL 0x0002 // new special key available
+#define KBD_NEW_ANY 0x0003 // any new key available
+
+#define KBD_ASCII 0x00FF // mask the special keys
+#define KBD_SPECIAL 0xFF00 // mask the ascii keys
+
+#define KBD_LOCALE 0x001C // bit mask for checking locales
+#define KBD_LOCALE_US 0x0000 // default: US keyboard layout
+#define KBD_LOCALE_DE 0x0004 // DE: German keyboard layout
+
+#define KBD_MODIFIERS 0x00E0 // bit mask for checking modifiers
+#define KBD_SHIFT 0x0020 // modifier "SHIFT" pressed
+#define KBD_ALT 0x0040 // modifier "ALT" pressed
+#define KBD_CTRL 0x0080 // modifier "CTRL" pressed
+
+// READ REGISTER: COMMON ASCII CODES
+
+#define KBD_SPACE 0x0020
+#define KBD_ENTER 0x000D
+#define KBD_ESC 0x001B
+#define KBD_TAB 0x0009
+#define KBD_BACKSPACE 0x0008
+
+// READ REGISTER: SPECIAL KEYS
+
+#define KBD_F1 0x0100
+#define KBD_F2 0x0200
+#define KBD_F3 0x0300
+#define KBD_F4 0x0400
+#define KBD_F5 0x0500
+#define KBD_F6 0x0600
+#define KBD_F7 0x0700
+#define KBD_F8 0x0800
+#define KBD_F9 0x0900
+#define KBD_F10 0x0A00
+#define KBD_F11 0x0B00
+#define KBD_F12 0x0C00
+
+#define KBD_CUR_UP 0x1000
+#define KBD_CUR_DOWN 0x1100
+#define KBD_CUR_LEFT 0x1200
+#define KBD_CUR_RIGHT 0x1300
+#define KBD_PG_UP 0x1400
+#define KBD_PG_DOWN 0x1500
+#define KBD_HOME 0x1600
+#define KBD_END 0x1700
+#define KBD_INS 0x1800
+#define KBD_DEL 0x1900
+
+// READ REGISTER: CTRL + character is also mapped to an ASCII code
+
+#define KBD_CTRL_A 0x0001
+#define KBD_CTRL_B 0x0002
+#define KBD_CTRL_C 0x0003
+#define KBD_CTRL_D 0x0004
+#define KBD_CTRL_E 0x0005
+#define KBD_CTRL_F 0x0006
+#define KBD_CTRL_G 0x0007
+#define KBD_CTRL_H 0x0008
+#define KBD_CTRL_I 0x0009
+#define KBD_CTRL_J 0x000A
+#define KBD_CTRL_K 0x000B
+#define KBD_CTRL_L 0x000C
+#define KBD_CTRL_M 0x000D
+#define KBD_CTRL_N 0x000E
+#define KBD_CTRL_O 0x000F
+#define KBD_CTRL_P 0x0010
+#define KBD_CTRL_Q 0x0011
+#define KBD_CTRL_R 0x0012
+#define KBD_CTRL_S 0x0013
+#define KBD_CTRL_T 0x0014
+#define KBD_CTRL_U 0x0015
+#define KBD_CTRL_V 0x0016
+#define KBD_CTRL_W 0x0017
+#define KBD_CTRL_X 0x0018
+#define KBD_CTRL_Y 0x0019
+#define KBD_CTRL_Z 0x001A
+
+//
+// Useful ASCII constants:
+//
+#define CHR_BELL 0x0007 // ASCII-BELL character
+#define CHR_TAB 0x0009 // ASCII-TAB character
+#define CHR_SPACE 0x0020 // ASCII-Space
+#define CHR_CR 0x000d // Carriage return
+#define CHR_LF 0x000a // Line feed
diff --git a/machines/rf12/machine.c b/machines/rf12/machine.c
new file mode 100755
index 0000000..40c6bc9
--- /dev/null
+++ b/machines/rf12/machine.c
@@ -0,0 +1,3808 @@
+/* Code generator for Motorola 68hc12 microcontrollers. */
+
+/*TODO:
+ regs_modified bei struct-copy
+ savings verfeinern
+ 4-Byte Copy
+ [static] testen
+ peephole-Pass um ALLOCREGs zu entfernen
+ ACC_IND (Achtung?)
+ struct-copy Problemfälle
+ banked
+ bit
+ long long, float, double, long double
+
+*/
+
+#include "supp.h"
+#include "vbc.h" /* nicht schoen, aber ... */
+
+static char FILE_[]=__FILE__;
+
+#include "dwarf2.c"
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc code-generator for 6809/6803/68hc12 V0.2 (c) in 2000-2022 by Volker Barthelmann";
+
+/* Commandline-flags the code-generator accepts */
+int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,
+ 0,0,0,0,
+ 0,0};
+char *g_flags_name[MAXGF]={"cpu","fpu","no-delayed-popping","const-in-data",
+ "merge-constants","no-peephole","mem-cse","acc-glob",
+ "pcrel","drel","no-char-addi2p","nodx","nou"};
+union ppi g_flags_val[MAXGF];
+
+/* Typenames (needed because of HAVE_EXT_TYPES). */
+char *typname[]={"strange","bit","char","short","int","long","long long",
+ "float","double","long double","void",
+ "near-pointer","far-pointer","huge-pointer",
+ "array","struct","union","enum","function"};
+
+int bitsperbyte = 8;
+int bytemask = 0xff;
+int dbl_bytemask = 0xffff;
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT of the target machine. */
+zmax char_bit;
+
+/* Sizes of all elementary types in bytes. */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. */
+char *regnames[]={"noreg","d","x","y","sp","u","d/x"};
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* Type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1]={0,1,1,0,1,0};
+
+int reg_prio[MAXR+1]={0,0,1,1,0,0};
+
+struct reg_handle empty_reg_handle={0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__interrupt","__dpage","__far",0};
+#define INTERRUPT 1
+#define DPAGE 2
+#define FAR 4
+
+int MINADDI2P=CHAR;
+
+/****************************************/
+/* Some private data and functions. */
+/****************************************/
+
+static long malign[MAX_TYPE+1]= {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+static long msizetab[MAX_TYPE+1]={0,1,1,2,2,4,4,4,4,4,0,2,4,4,0,0,0,2,0};
+
+struct Typ ityp={SHORT},ltyp={LONG};
+
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static int section=-1,newobj,scnt,pushed_acc;
+static char *codename="\t.text\n",
+ *dataname="\t.data\n",
+ *bssname="\t.section\t.bss\n",
+ *rodataname="\t.section\t.rodata\n";
+
+#define IMM_IND 1
+#define VAR_IND 2
+#define POST_INC 3
+#define POST_DEC 4
+#define PRE_INC 5
+#define PRE_DEC 6
+#define ACC_IND 7
+#define KONSTINC 8
+
+/* (user)stack-pointer, pointer-tmp, int-tmp; reserved for compiler */
+static int acc=1,ix=2,iy=3,sp=4,iu=5,dx=6;
+static void pr(FILE *,struct IC *);
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+static char *marray[]={"__section(x,y)=__vattr(\"section(\"#x\",\"#y\")\")",
+ "__HC12__",
+ "__SIZE_T_INT=1",
+ "__direct=__vattr(\"section(\\\"dpage\\\")\")",
+ 0};
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static long loff,roff,stackoffset,notpopped,dontpop,maxpushed,stack;
+
+static char *x_t[]={"?","","b","","","","","","","","","","","","","",""};
+static char *ccs[]={"eq","ne","lt","ge","le","gt"};
+static char *uccs[]={"eq","ne","lo","hs","ls","hi"};
+static char *logicals[]={"ora","eor","and"};
+static char *dct[]={"",".bit",".byte",".2byte",".2byte",".4byte",".8byte",".4byte",".8byte",".8byte",
+ "(void)",".2byte",".34byte",".34byte"};
+static char *idprefix="",*labprefix=".l";
+static int exit_label,have_frame;
+static char *ret;
+static int stackchecklabel;
+static int frame_used,stack_valid;
+static int CPU=6812;
+static int pcrel,drel;
+static int skip_rel;
+static char *jsrinst="jsr";
+static char *jmpinst="jmp";
+static int nodx,nou;
+int switchsubs;
+
+static int cc_t;
+static struct obj *cc;
+
+static struct obj mobj;
+
+#define STR_NEAR "near"
+#define STR_FAR "far"
+#define STR_HUGE "huge"
+#define STR_BADDR "baddr"
+
+#define ISNULL() (zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
+#define ISLWORD(t) ((t&NQ)==LONG||(t&NQ)==FPOINTER||(t&NQ)==HPOINTER||(t&NQ)==FLOAT)
+#define ISHWORD(t) ((t&NQ)==INT||(t&NQ)==SHORT||(t&NQ)==NPOINTER)
+#define ISCHWORD(t) ((t&NQ)==CHAR||ISHWORD(t))
+#define ISSTATIC(v) ((v)->storage_class==EXTERN||(v)->storage_class==STATIC)
+#define ISBADDR(v) ((v)->vtyp->attr&&strstr(STR_BADDR,(v)->vtyp->attr))
+/*FIXME*/
+#define ISFAR(v) ((v)->vtyp->attr&&(strstr(STR_FAR,(v)->vtyp->attr)||strstr(STR_HUGE,(v)->vtyp->attr)))
+
+#define ISACC(x) ((x)==acc)
+#define ISX(x) ((x)==ix)
+#define ISY(x) ((x)==iy)
+#define ISU(x) ((x)==iu)
+#define ISIDX(x) (ISX(x)||ISY(x)||(ISU(x)&&CPU!=6812))
+#define ISRACC(x) (isreg(x)&&ISACC(p->x.reg))
+#define ISRX(x) (isreg(x)&&ISX(p->x.reg))
+#define ISRY(x) (isreg(x)&&ISY(p->x.reg))
+#define ISRU(x) (isreg(x)&&ISU(p->x.reg))
+#define ISRIDX(x) (isreg(x)&&ISIDX(p->x.reg))
+
+#define CPUOPT ((g_flags[0]&USEDFLAG)?g_flags_val[0].l:6812)
+
+#define SPUSH(x) (CPU==6812?"\tpsh" x "\n":"\tpshs\t" x "\n")
+#define SPUSHD (CPU==6812?"\tpshd\n":"\tpshs\tb,a\n")
+#define SPULL(x) (CPU==6812?"\tpul" x "\n":"\tpuls\t" x "\n")
+#define SPULLD (CPU==6812?"\tpuld\n":"\tpuls\ta,b\n")
+#define SCMP(x) (CPU==6812?"\tcp" x "\t":"\tcmp" x "\t")
+#define SEX (CPU==6812?"\tsex\tb,d\n":"\tsex\n")
+
+#define SGN16(x) (zm2l(zi2zm(zm2zi(l2zm((long)(x))))))
+
+enum peepf { NEEDSAME = 1, REMOVE1ST = 2, ALLOWSFX = 4};
+struct peeps {char *s1,*s2,*r;enum peepf flags;};
+
+static int check_sfx(char *s)
+{
+ if(!*s) return 0;
+ s+=strlen(s)-1;
+ if(*s=='+'||*s=='-') return 1;
+ if(*s!='s'&&*s!='x'&&*s!='y'&&*s!='u') return 0;
+ s--;
+ if(*s!=',') return 0;
+ s--;
+ if(*s=='+'||*s=='-') return 1;
+ return 0;
+}
+
+static int setszflag(char *op,char r)
+{
+ static char *zb[]={"adcb","addb","andb","aslb","asrb","clrb","comb","decb","eorb","incb",
+ "ldab","ldb","lslb","lsrb","negb","orb","orab","rolb","rorb","sbcb",
+ "stb","stab","subb","tstb"};
+ static char *zd[]={"addd","ldd","sex","std","subd"};
+
+ int i;
+
+ if(r=='b'){
+ for(i=0;i<sizeof(zb)/sizeof(*zb);i++)
+ if(!strcmp(op,zb[i]))
+ return 1;
+ }
+ if(r=='d'){
+ for(i=0;i<sizeof(zd)/sizeof(*zd);i++)
+ if(!strcmp(op,zd[i]))
+ return 1;
+ }
+ if(r=='x'&&(!strcmp(op,"leax")||!strcmp(op,"ldx"))) return 1;
+ if(r=='y'&&(!strcmp(op,"leay")||!strcmp(op,"ldy"))) return 1;
+ if(CPU==6812){
+ if(r=='x'&&(!strcmp(op,"dex")||!strcmp(op,"inx"))) return 1;
+ if(r=='y'&&(!strcmp(op,"dey")||!strcmp(op,"iny"))) return 1;
+ }
+ return 0;
+}
+
+int emit_peephole(void)
+{
+ int entries,i,j,v1,v2;
+ char *asmline[EMIT_BUF_DEPTH];
+ char buf1[1024],buf2[1024];
+ char op1[8],op2[8];
+
+
+ /* TODO: adapt better */
+ static struct peeps elim[]={
+ "lda","sta",0,NEEDSAME,
+ "ldb","stb",0,NEEDSAME,
+ "ldaa","staa",0,NEEDSAME,
+ "ldab","stab",0,NEEDSAME,
+ "ldd","std",0,NEEDSAME,
+ "ldx","stx",0,NEEDSAME,
+ "ldy","sty",0,NEEDSAME,
+ "ldu","stu",0,NEEDSAME,
+ "sta","sta",0,NEEDSAME,
+ "stb","stb",0,NEEDSAME,
+ "staa","staa",0,NEEDSAME,
+ "stab","stab",0,NEEDSAME,
+ "std","std",0,NEEDSAME,
+ "stx","stx",0,NEEDSAME,
+ "sty","sty",0,NEEDSAME,
+ "stu","stu",0,NEEDSAME,
+ "sta","lda",0,NEEDSAME,
+ "stb","ldb",0,NEEDSAME,
+ "staa","ldaa",0,NEEDSAME,
+ "stab","ldab",0,NEEDSAME,
+ "std","ldd",0,NEEDSAME,
+ "stx","ldx",0,NEEDSAME,
+ "sty","ldy",0,NEEDSAME,
+ "stu","ldu",0,NEEDSAME,
+#if 0
+ "lda","lda",0,REMOVE1ST,
+ "ldaa","ldaa",0,REMOVE1ST,
+ "ldab","ldab",0,REMOVE1ST,
+ "ldb","ldb",0,REMOVE1ST,
+ "ldd","ldd",0,REMOVE1ST,
+ "ldx","ldx",0,REMOVE1ST,
+ "ldy","ldy",0,REMOVE1ST,
+ "ldu","ldu",0,REMOVE1ST,
+ "lda","pla",0,REMOVE1ST,
+ "lda","txa",0,REMOVE1ST,
+ "lda","tya",0,REMOVE1ST,
+ "ldx","tax",0,REMOVE1ST,
+ "ldy","tay",0,REMOVE1ST,
+ "tay","ldy",0,REMOVE1ST,
+ "tax","ldx",0,REMOVE1ST,
+ "txa","lda",0,REMOVE1ST,
+ "tya","lda",0,REMOVE1ST,
+#endif
+ };
+
+
+ i=emit_l;
+ if(emit_f==0)
+ entries=i-emit_f+1;
+ else
+ entries=EMIT_BUF_DEPTH;
+ asmline[0]=emit_buffer[i];
+ if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"cmpb")&&!strcmp(buf1,"#0"))
+ strcpy(asmline[0],"\ttstb\n");
+ if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"cmpd")&&!strcmp(buf1,"#0"))
+ strcpy(asmline[0],"\tsubd\t#0\n");
+
+ if(entries>=2){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[1]=emit_buffer[i];
+
+ for(j=0;j<sizeof(elim)/sizeof(elim[0]);j++){
+ if(elim[j].flags&NEEDSAME){
+ if(sscanf(asmline[0]," %6s %999s",op2,buf2)==2&&
+ sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&
+ !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)&&
+ !strcmp(buf1,buf2)){
+ if(!check_sfx(buf1)&&!check_sfx(buf2)){
+ if(elim[j].r){
+ strcpy(asmline[0],elim[j].r);
+ }else{
+ if(elim[j].flags&REMOVE1ST)
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ }
+ return 1;
+ }
+ }
+ }else{
+ *buf1=0;*buf2=0;
+ if(sscanf(asmline[1]," %6s %999s",op1,buf1)>=1&&
+ sscanf(asmline[0]," %6s %999s",op2,buf2)>=1&&
+ !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)){
+ if((elim[j].flags&ALLOWSFX)||(!check_sfx(buf1)&&!check_sfx(buf2))){
+ if(elim[j].flags&REMOVE1ST)
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return 1;
+ }
+ }
+ }
+ }
+
+ if(!strcmp(asmline[0],"\trts\n")&&sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"puls")){
+ sprintf(asmline[1]+strlen(asmline[1])-1,",pc\n");
+ remove_asm();
+ return 1;
+ }
+
+ if(!strcmp(asmline[0],"\tstb\t0,s\n")&&!strcmp(asmline[1],"\tleas\t-1,s\n")){
+ strcpy(asmline[1],"\tpshs\tb\n");
+ remove_asm();
+ return 1;
+ }
+
+ if(!strcmp(asmline[0],"\tstd\t0,s\n")&&!strcmp(asmline[1],"\tleas\t-2,s\n")){
+ strcpy(asmline[1],"\tpshs\tb,a\n");
+ remove_asm();
+ return 1;
+ }
+
+ if(!strcmp(asmline[0],"\tldb\t0,s\n")&&!strcmp(asmline[1],"\tpshs\tb\n")){
+ remove_asm();
+ return 1;
+ }
+
+ if(!strcmp(asmline[0],"\tldd\t0,s\n")&&!strcmp(asmline[1],"\tpshs\tb,a\n")){
+ remove_asm();
+ return 1;
+ }
+
+ if(!strcmp(asmline[0],"\tpshs\tb,a\n")&&!strcmp(asmline[1],"\tpuls\ta,b\n")){
+ strcpy(asmline[1],"\tldd\t0,s\n");
+ remove_asm();
+ return 1;
+ }
+
+ if(sscanf(asmline[1]," ldd %999s",op1)>=1&&sscanf(asmline[0]," ldd %999s",op2)>=1){
+ if(!((op2[0]=='a'||op2[0]=='b'||op2[0]=='d')&&op2[1]==',')){
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return 1;
+ }
+ }
+
+ if(!strcmp(asmline[0],"\ttfr\tx,d\n")&&!strcmp(asmline[1],"\ttfr\td,x\n")){
+ remove_asm();
+ return 1;
+ }
+ if(!strcmp(asmline[0],"\ttfr\ty,d\n")&&!strcmp(asmline[1],"\ttfr\td,y\n")){
+ remove_asm();
+ return 1;
+ }
+ if(!strcmp(asmline[0],"\tstd\t0,sp\n")&&!strcmp(asmline[1],"\tpshd\n")){
+ remove_asm();
+ return 1;
+ }
+ if(!strcmp(asmline[0],"\tldd\t0,sp\n")&&!strcmp(asmline[1],"\tpshd\n")){
+ remove_asm();
+ return 1;
+ }
+
+ if(sscanf(asmline[0]," leas %d,s",&v1)==1&&sscanf(asmline[1]," leas %d,s",&v2)==1){
+ sprintf(asmline[1],"\tleas\t%ld,s\n",SGN16(v1+v2));
+ remove_asm();
+ return 1;
+ }
+
+ if(CPU!=6812&&sscanf(asmline[0]," tfr %c,%c",buf1,buf2)==2){
+ if((*buf1=='x'||*buf1=='y'||*buf1=='u'||*buf1=='s')&&
+ (*buf2=='x'||*buf2=='y'||*buf2=='u'||*buf2=='s')){
+ sprintf(asmline[0],"\tlea%c\t,%c\n",*buf2,*buf1);
+ }
+ }
+ if(CPU==6812&&(!strcmp(asmline[1],"\tdex\n")||!strcmp(asmline[1],"\tdey\n")||!strcmp(asmline[1],"\tsubd\t#1\n"))&&
+ (!strncmp(asmline[0],"\tbne\t",5)||!strncmp(asmline[0],"\tbeq\t",5))){
+ char r=asmline[1][3];
+ if(r=='b') r='d';
+ strcpy(asmline[1],"\td");
+ strncpy(asmline[1]+2,asmline[0]+1,4);
+ asmline[1][6]=r;asmline[1][7]=',';
+ strcpy(asmline[1]+8,asmline[0]+5);
+ remove_asm();
+ return 1;
+ }
+ if(CPU==6812&&(!strcmp(asmline[1],"\tinx\n")||!strcmp(asmline[1],"\tiny\n")||!strcmp(asmline[1],"\taddd\t#1\n"))&&
+ (!strncmp(asmline[0],"\tbne\t",5)||!strncmp(asmline[0],"\tbeq\t",5))){
+ char r=asmline[1][3];
+ strcpy(asmline[1],"\ti");
+ strncpy(asmline[1]+2,asmline[0]+1,4);
+ asmline[1][6]=r;asmline[1][7]=',';
+ strcpy(asmline[1]+8,asmline[0]+5);
+ remove_asm();
+ return 1;
+ }
+ }
+ if(entries>=3){
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[2]=emit_buffer[i];
+ if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2){
+ if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){
+ if(!strcmp(asmline[1],"\ttstb\n")||!strcmp(asmline[1],"\tcpb\t#0\n")){
+ if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+ setszflag(op2,'b')){
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return 1;
+ }
+ }
+ if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+ (!strcmp(op2,"subd")||!strcmp(op2,"cpd"))&&!strcmp(buf2,"#0")){
+ if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+ setszflag(op2,'d')){
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return 1;
+ }
+ }
+ if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+ !strcmp(op2,(CPU==6812)?"cpx":"cmpx")&&!strcmp(buf2,"#0")){
+ if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+ setszflag(op2,'x')){
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return 1;
+ }
+ }
+ if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
+ !strcmp(op2,(CPU==6812)?"cpy":"cmpy")&&!strcmp(buf2,"#0")){
+ if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
+ setszflag(op2,'y')){
+ strcpy(asmline[1],asmline[0]);
+ remove_asm();
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int special_section(FILE *f,struct Var *v)
+{
+ char *sec;
+ if(v->tattr&DPAGE){
+ emit(f,"\t.section\t.dpage\n");
+ }else{
+ if(!v->vattr) return 0;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return 0;
+ sec+=strlen("section(");
+ emit(f,"\t.section\t");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ }
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+static struct fpconstlist {
+ struct fpconstlist *next;
+ int label,typ;
+ union atyps val;
+} *firstfpc;
+
+static int addfpconst(struct obj *o,int t)
+{
+ struct fpconstlist *p=firstfpc;
+ t&=NQ;
+ if(g_flags[4]&USEDFLAG){
+ for(p=firstfpc;p;p=p->next){
+ if(t==p->typ){
+ eval_const(&p->val,t);
+ if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
+ if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
+ if(t==LDOUBLE&&zldeqto(vldouble,o->val.vldouble)) return p->label;
+ }
+ }
+ }
+ p=mymalloc(sizeof(struct fpconstlist));
+ p->next=firstfpc;
+ p->label=++label;
+ p->typ=t;
+ p->val=o->val;
+ firstfpc=p;
+ return p->label;
+}
+
+int pointer_type(struct Typ *p)
+{
+ if(!p) ierror(0);
+ while((p->flags&NQ)==ARRAY) p=p->next;
+ if((p->flags&NQ)==FUNKT) {
+ if(p->attr)
+ if(strstr(p->attr,STR_FAR)) return FPOINTER;
+ if (p->flags&FAR)
+ return FPOINTER;
+ return NPOINTER; /*FIXME: banked*/
+ }
+ if(p->attr){
+ if(strstr(p->attr,STR_HUGE)) return HPOINTER;
+ if(strstr(p->attr,STR_FAR)) return FPOINTER;
+ if(strstr(p->attr,STR_NEAR)) return NPOINTER;
+ }
+ /*FIXME*/
+ return NPOINTER;
+}
+static long voff(struct obj *p)
+{
+ if(zm2l(p->v->offset)<0)
+ return loff-zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset+1;
+ else
+ return zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset;
+}
+
+static void emit_obj(FILE *f,struct obj *p,int t)
+/* Gibt Objekt auf Bildschirm aus */
+{
+ if(p->am){
+ int flags=p->am->flags;
+ if(flags==ACC_IND){
+ emit(f,"%s,%s",regnames[acc],regnames[p->am->base]);
+ return;
+ }
+ if(flags==KONSTINC){
+ eval_const(&p->val,p->am->base);
+ if((t&NQ)==CHAR){
+ vumax=zumrshift(vumax,bitsperbyte*3-bitsperbyte*p->am->offset);
+ vumax=zumand(vumax,ul2zum(tu_max[CHAR]));
+ }else{
+ vumax=zumrshift(vumax,bitsperbyte*2-bitsperbyte*p->am->offset);
+ vumax=zumand(vumax,ul2zum(tu_max[SHORT]));
+ }
+ emit(f,"#%lu",zum2ul(vumax));
+ return;
+ }
+ if(flags<POST_INC||flags>PRE_DEC||CPU==6812)
+ emit(f,"%ld",p->am->offset&tu_max[SHORT]);
+ if(p->am->v){
+ if(p->am->v->storage_class==STATIC)
+ emit(f,"+%s%ld",labprefix,zm2l(p->am->v->offset));
+ else
+ emit(f,"+(%s%s)",idprefix,p->am->v->identifier);
+ }
+ emit(f,",");
+ if(flags==PRE_INC){
+ emit(f,"+");
+ if(p->am->offset==2&&CPU!=6812) emit(f,"+");
+ }else if(flags==PRE_DEC){
+ emit(f,"-");
+ if(p->am->offset==2&&CPU!=6812) emit(f,"-");
+ }
+ emit(f,"%s",regnames[p->am->base]);
+ if(flags==POST_INC){
+ emit(f,"+");
+ if(p->am->offset==2&&CPU!=6812) emit(f,"+");
+ }else if(flags==POST_DEC){
+ emit(f,"-");
+ if(p->am->offset==2&&CPU!=6812) emit(f,"-");
+ }
+ return;
+ }
+ if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if(p->flags&VARADR) emit(f,"#");
+ if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,"0,");
+ if((p->flags&(DREFOBJ|REG))==DREFOBJ) emit(f,"[");
+ if((p->flags&(VAR|REG))==VAR){
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+ emit(f,"%ld,%s",voff(p),regnames[sp]);
+ }else{
+ if(!zmeqto(l2zm(0L),p->val.vmax)){
+ emit(f,"%ld",zm2l(zi2zm(zm2zi(p->val.vmax))));
+ emit(f,"+");
+ }
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"(%s%s)",idprefix,p->v->identifier);
+ }
+ if(pcrel&&!(p->flags&VARADR)&&ISFUNC(p->v->vtyp->flags))
+ emit(f,",pc");
+ if(drel&&!(p->flags&VARADR)&&!ISFUNC(p->v->vtyp->flags)){
+ if(CPU==6812) ierror(0);
+ emit(f,",%s",regnames[iu]);
+ }
+ }
+ }
+ if(p->flags®){
+ if(ISACC(p->reg)&&(t&NQ)==CHAR)
+ emit(f,"b");
+ else
+ emit(f,"%s",regnames[p->reg]);
+ }
+ if(p->flags&KONST){
+ if(ISFLOAT(t)){
+ emit(f,"%s%d",labprefix,addfpconst(p,t));
+ }else{
+ emit(f,"#");emitval(f,&p->val,t&NU);
+ }
+ }
+ if((p->flags&(DREFOBJ|REG))==DREFOBJ){
+ if(p->v->storage_class==EXTERN||p->v->storage_class==STATIC){
+ if(is_const(p->v->vtyp)){
+ if(!pcrel&&CPU==6812) emit(f,",pc");
+ }else{
+ if(!drel&&CPU==6812) emit(f,",pc");
+ }
+ }
+ emit(f,"]");
+ }
+}
+
+static void dwarf2_print_frame_location(FILE *f,struct Var *v)
+{
+ /*FIXME: needs a location list and correct register translation */
+ struct obj o;
+ o.flags=REG;
+ o.reg=sp;
+ o.val.vmax=l2zm(0L);
+ o.v=0;
+ dwarf2_print_location(f,&o);
+}
+static int dwarf2_regnumber(int r)
+{
+ /*FIXME: always returns D as accumulator, even if byte size */
+ static int dwarf_regs[MAXR+1]={-1,3,7,8,15};
+ return dwarf_regs[r];
+}
+static zmax dwarf2_fboffset(struct Var *v)
+{
+ /*FIXME*/
+ if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0);
+ if(!zmleq(l2zm(0L),v->offset))
+ return l2zm((long)(loff-zm2l(v->offset)));
+ else
+ return v->offset;
+}
+
+/* test operand for mov instruction */
+static int mov_op(struct obj *o)
+{
+ long off;
+ if(CPU!=6812) return 0;
+ if(o->am){
+ int f=o->am->flags;
+ if(f==POST_INC||f==PRE_INC||f==POST_DEC||f==PRE_DEC||f==ACC_IND)
+ return 1;
+ if(f==IMM_IND){
+ if(o->am->v) return 0;
+ off=o->am->offset;
+ if(off>=-256&&off<=255)
+ return 1;
+ else
+ return 0;
+ }
+ ierror(0);
+ }
+ if(o->flags&(KONST|VARADR)) return 1;
+ if((o->flags&(REG|DREFOBJ))==(REG|DREFOBJ)) return 1;
+ if((o->flags&(VAR|REG|DREFOBJ))==VAR){
+ if(o->v->storage_class==STATIC||o->v->storage_class==EXTERN)
+ return 1;
+ off=voff(o);
+ if(off>=-256&&off<=255)
+ return 1;
+ else
+ return 0;
+ }
+ return 0;
+}
+
+/* add an offset to an object describing a memory address */
+static void inc_addr(struct obj *o,long val,int t)
+{
+ if(o->am){
+ int f=o->am->flags;
+ if(f==IMM_IND||f==KONSTINC)
+ o->am->offset+=val;
+ else if(f==POST_INC||f==POST_DEC||f==PRE_INC||f==PRE_DEC){
+ struct AddressingMode *old=o->am;
+ o->am=mymalloc(sizeof(*o->am));
+ o->am->flags=IMM_IND;
+ o->am->base=old->base;
+ o->am->v=0;
+ if(f==POST_DEC) o->am->offset=old->offset-val;
+ else if(f==POST_INC) o->am->offset=-old->offset+val;
+ else if(f==PRE_DEC) o->am->offset=val;
+ else o->am->offset=-val;
+ }else
+ ierror(0);
+ }else if(o->flags&DREFOBJ){
+ struct AddressingMode *am;
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ if(!o->reg) ierror(0);
+ am->base=o->reg;
+ am->offset=zm2l(val);
+ am->v=0;
+ }else if(o->flags&KONST){
+ struct AddressingMode *am;
+ if(o->am) ierror(0);
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=KONSTINC;
+ am->offset=zm2l(val);
+ am->base=t;
+ }else{
+ o->val.vmax=zmadd(o->val.vmax,val);
+ }
+}
+
+/* pushed on the stack by a callee, no pop needed */
+static void callee_push(long l)
+{
+ if(l-stackoffset>stack)
+ stack=l-stackoffset;
+}
+static void push(long l)
+{
+ stackoffset-=l;
+ if(stackoffset<maxpushed) maxpushed=stackoffset;
+ if(-maxpushed>stack) stack=-maxpushed;
+}
+static void pop(long l)
+{
+ stackoffset+=l;
+}
+static void gen_pop(FILE *f,long l)
+{
+ if(l==0) return;
+ if(l==1&&CPU==6812){
+ emit(f,"\tins\n");
+#if 0 /* might clobber return register */
+ }else if(l==2&&!regs[acc]){
+ emit(f,SPULLD);
+ BSET(regs_modified,acc);
+ }else if(l==2&&!regs[ix]){
+ emit(f,SPULL("x"));
+ BSET(regs_modified,ix);
+ }else if(l==2&&!regs[iy]){
+ emit(f,SPULL("y"));
+ BSET(regs_modified,iy);
+#endif
+ }else{
+ emit(f,"\tleas\t%u,%s\n",SGN16(l),regnames[sp]);
+ }
+ pop(l);
+}
+static void pr(FILE *f,struct IC *p)
+{
+ int r;
+ if(pushed_acc){
+ emit(f,SPULLD);
+ pop(2);
+ pushed_acc=0;
+ }
+ for(r=MAXR;r>=1;r--){
+ if(regs[r]&8){
+ emit(f,"\t%s%s\n",CPU==6812?"pul":"puls\t",regnames[r]);
+ pop(2);
+ }
+ regs[r]&=~12;
+ }
+}
+static void function_top(FILE *f,struct Var *v,long offset)
+/* erzeugt Funktionskopf */
+{
+ int i;
+ emit(f,"# offset=%ld\n",offset);
+ have_frame=0;stack_valid=1;stack=0;
+ if(!special_section(f,v)&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else{
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }
+ roff=0;
+ for(i=MAXR;i>0;i--){
+ if(regused[i]&&!regscratch[i]&&!regsa[i]){
+ have_frame=1;
+ loff+=2;
+ roff+=2;
+ if(i==iy) emit(f,SPUSH("y"));
+ else if(i==iu){
+ if(CPU!=6812&®used[iy]){
+ emit(f,"\tpshs\tu,y\n");
+ loff+=2;roff+=2;i=iy;
+ }else
+ emit(f,SPUSH("u"));
+ }else
+ ierror(0);
+ }
+ }
+ if(stack_check){
+ stackchecklabel=++label;
+ emit(f,"\tldy\t#%s%d\n",labprefix,stackchecklabel);
+ /* FIXME: banked */
+ emit(f,"\t%s\t%s__stack_check\n",jsrinst,idprefix);
+ }
+ if(offset){
+ if(CPU==6812&&offset==1)
+ emit(f,SPUSH("b"));
+ else if(CPU==6812&&offset==2)
+ emit(f,SPUSHD);
+ else
+ emit(f,"\tleas\t%ld,%s\n",SGN16(-offset),regnames[sp]);
+ have_frame=1;
+ }
+}
+static void function_bottom(FILE *f,struct Var *v,long offset)
+/* erzeugt Funktionsende */
+{
+ int i;
+ offset-=roff;
+ if(offset){
+ if(offset==1&&CPU==6812)
+ emit(f,"\tins\n");
+ else if(offset==2&&CPU==6812&&!zmeqto(szof(v->vtyp->next),l2zm(4L)))
+ emit(f,SPULL("x"));
+ else if(offset==2&&CPU==6812&®used[iy])
+ emit(f,SPULL("y"));
+ else
+ emit(f,"\tleas\t%ld,%s\n",SGN16(offset),regnames[sp]);
+ }
+ for(i=1;i<=MAXR;i++){
+ if(regused[i]&&!regscratch[i]&&!regsa[i]){
+ have_frame=1;
+ if(i==iy){
+ if(CPU!=6812&®used[iu]&&!regscratch[iu]&&!regsa[iu]){
+ emit(f,"\tpuls\tu,y\n");
+ i=iu;
+ }else
+ emit(f,SPULL("y"));
+ }else if(i==iu) emit(f,SPULL("u"));
+ else
+ ierror(0);
+ }
+ }
+ if(ret) emit(f,"\t%s\n",ret);
+ if(v->storage_class==EXTERN){
+ emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
+ emit(f,"\t.size\t%s%s,$-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
+ }else{
+ emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset));
+ emit(f,"\t.size\t%s%ld,$-%s%ld\n",labprefix,zm2l(v->offset),labprefix,zm2l(v->offset));
+ }
+ if(stack_check)
+ emit(f,"\t.equ\t%s%d,%ld\n",labprefix,stackchecklabel,offset-maxpushed);
+ if(stack_valid){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=l2zm(stack+offset);
+ emit(f,"# stacksize=%ld\n",stack+offset);
+ emit(f,"\t.equ\t%s__stack_%s,%ld\n",idprefix,v->identifier,stack+offset);
+ }
+}
+static int compare_objects(struct obj *o1,struct obj *o2)
+{
+ if(o1->flags==o2->flags&&o1->am==o2->am){
+ if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
+ if(!(o1->flags®)||o1->reg==o2->reg){
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/*FIXME*/
+static void clear_ext_ic(struct ext_ic *p)
+{
+ p->flags=0;
+ p->r=0;
+ p->offset=0;
+}
+static long pof2(zumax x)
+/* Yields log2(x)+1 oder 0. */
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+static void peephole(struct IC *p)
+{
+ int c,c2,r,t;struct IC *p2;
+ struct AddressingMode *am;
+ zmax incmin,incmax;
+ if(CPU==6812){
+ incmin=l2zm(-8L);
+ incmax=l2zm(8L);
+ }else{
+ incmin=l2zm(-2L);
+ incmax=l2zm(2L);
+ }
+ frame_used=0;
+ for(;p;p=p->next){
+ c=p->code;
+ if(!frame_used){
+ if((p->q1.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q1.v)) frame_used=1;
+ if((p->q2.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q2.v)) frame_used=1;
+ if((p->z.flags&(REG|VAR))==VAR&&!ISSTATIC(p->z.v)) frame_used=1;
+ }
+ /* letztes Label merken */
+ if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+ if(c==LABEL) exit_label=p->typf;
+#if 0
+ /* and x,#const;bne/beq, FIXME */
+ if(c==AND&&isconst(q2)&&isreg(z)){
+ long bit;
+ eval_const(&p->q2.val,p->typf);
+ if(bit=pof2(vumax)){
+ struct IC *cmp=0;int fr=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==TEST){
+ if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg){
+ cmp=p2;continue;
+ }
+ }
+ if(c2==COMPARE&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,p2->typf);
+ if(ISNULL()){
+ cmp=p2;continue;
+ }
+ break;
+ }
+ if(c2==FREEREG&&p2->q1.reg==p->z.reg) {fr++;continue;}
+ if((c2==BNE||c2==BEQ)&&cmp&&fr==1){
+ p->ext.flags=EXT_IC_BTST;
+ p2->ext.flags=EXT_IC_BTST;
+ p2->ext.offset=bit-1;
+ cmp->code=NOP;
+ cmp->q1.flags=cmp->q2.flags=cmp->z.flags=0;
+ break;
+ }
+ if(((p2->q1.flags®)&&p2->q1.reg==p->z.reg)||((p2->q2.flags®)&&p2->q2.reg==p->z.reg)||((p2->z.flags®)&&p2->z.reg==p->z.reg)) break;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ }
+ }
+ }
+#endif
+ /* Try d,idx */
+ if(c==ADDI2P&&ISRACC(q2)&&ISRIDX(z)&&(ISRIDX(q1)||p->q2.reg!=p->z.reg)){
+ int base,idx;struct obj *o;
+ r=p->z.reg;idx=p->q2.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||!ISCHWORD(q1typ(p2))) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ break; /*TODO: check what is possible */
+ if(o||!ISCHWORD(q2typ(p2))) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ break; /*TODO: check what is possible */
+ if(o||!ISCHWORD(ztyp(p2))) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=ACC_IND;
+ am->base=base;
+ if(idx!=acc) ierror(0);
+ am->offset=idx;
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ /* better no instructions between, accu used too much */
+ if(c2!=FREEREG&&c2!=ALLOCREG&&!o) break;
+ }
+ }
+ /* POST_INC/DEC in q1 */
+ if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ r=p->q1.reg; t=q1typ(p);
+ if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q2.flags®)||p->q2.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,p2->typf2);
+ if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+ if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ p->q1.am=mymalloc(sizeof(*am));
+ p->q1.am->base=r;
+ p->q1.am->v=0;
+ if(zmleq(vmax,l2zm(0L))){
+ p->q1.am->flags=POST_DEC;
+ p->q1.am->offset=-zm2l(vmax);
+ }else{
+ p->q1.am->flags=POST_INC;
+ p->q1.am->offset=zm2l(vmax);
+ }
+ }else break;
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(((p2->q1.flags®)&&p2->q1.reg==r)||((p2->q2.flags®)&&p2->q2.reg==r)||((p2->z.flags®)&&p2->z.reg==r)) break;
+ }
+ }
+ }
+ /* POST_INC/DEC in q2 */
+ if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ r=p->q2.reg; t=q2typ(p);
+ if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q1.flags®)||p->q1.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,p2->typf2);
+ if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+ if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ p->q2.am=mymalloc(sizeof(*am));
+ p->q2.am->base=r;
+ p->q2.am->v=0;
+ if(zmleq(vmax,l2zm(0L))){
+ p->q2.am->flags=POST_DEC;
+ p->q2.am->offset=-zm2l(vmax);
+ }else{
+ p->q2.am->flags=POST_INC;
+ p->q2.am->offset=zm2l(vmax);
+ }
+ }else break;
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(((p2->q1.flags®)&&p2->q1.reg==r)||((p2->q2.flags®)&&p2->q2.reg==r)||((p2->z.flags®)&&p2->z.reg==r)) break;
+ }
+ }
+ }
+ /* POST_INC/DEC in z */
+ if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ r=p->z.reg; t=ztyp(p);
+ if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q1.flags®)||p->q1.reg!=r)&&(!(p->q2.flags®)||p->q2.reg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,p2->typf2);
+ if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
+ if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ p->z.am=mymalloc(sizeof(*am));
+ p->z.am->base=r;
+ p->z.am->v=0;
+ if(zmleq(vmax,l2zm(0L))){
+ p->z.am->flags=POST_DEC;
+ p->z.am->offset=-zm2l(vmax);
+ }else{
+ p->z.am->flags=POST_INC;
+ p->z.am->offset=zm2l(vmax);
+ }
+ }else break;
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(((p2->q1.flags®)&&p2->q1.reg==r)||((p2->q2.flags®)&&p2->q2.reg==r)||((p2->z.flags®)&&p2->z.reg==r)) break;
+ }
+ }
+ }
+
+ /* R,#c */
+ if((c==ADDI2P||c==SUBIFP)&&ISHWORD(p->typf)&&((p->typf2&NQ)==NPOINTER||(p->typf2&NQ)==FPOINTER)&&isreg(z)&&((p->q2.flags&(KONST|DREFOBJ))==KONST||(!drel&&(p->q1.flags&VARADR)))){
+ int base;zmax of;struct obj *o;struct Var *v;
+ if(p->q1.flags&VARADR){
+ v=p->q1.v;
+ of=p->q1.val.vmax;
+ r=p->z.reg;
+ if(isreg(q2)&&ISIDX(p->q2.reg))
+ base=p->q2.reg;
+ else
+ base=r;
+ }else{
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ v=0;
+ r=p->z.reg;
+ if(isreg(q1)&&ISIDX(p->q1.reg)) base=p->q1.reg; else base=r;
+ }
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||!ISHWORD(q1typ(p2))) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||!ISHWORD(q2typ(p2))) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||!ISHWORD(ztyp(p2))) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ am->base=base;
+ am->offset=zm2l(of);
+ am->v=v;
+ if(!v){
+ if(isreg(q1)&&ISIDX(p->q1.reg)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }else{
+ if(isreg(q2)&&ISIDX(p->q2.reg)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q1=p->q2;p->q2.flags=0;
+ p->q2.val.vmax=sizetab[p->typf&NQ];
+ }
+ }
+ }
+ break;
+ }
+ if(/*get_reg!! c2!=FREEREG&&*/m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+}
+
+static struct obj *cam(int flags,int base,long offset,struct Var *v)
+/* Initializes an addressing-mode structure and returns a pointer to */
+/* that object. Will not survive a second call! */
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ am.offset=offset;
+ am.v=v;
+ return &obj;
+}
+
+static void get_acc(FILE *f,struct IC *p)
+{
+ if(regs[acc]){
+ if(p->q2.am)
+ if(p->q2.am->flags==ACC_IND) ierror(0);
+ else
+ if((p->q2.flags®)&&ISACC(p->q2.reg)) ierror(0);
+ if(p->z.am)
+ if(p->z.am->flags==ACC_IND) ierror(0);
+ else
+ if((p->z.flags®)&&ISACC(p->z.reg)) ierror(0);
+ if(regs[acc]){
+ emit(f,SPUSHD);
+ push(2);
+ pushed_acc=1;
+ }
+ }
+}
+static int get_idx(FILE *f,IC *p)
+{
+ int r;
+ for(r=1;r<=MAXR;r++){
+ if(ISIDX(r)){
+ if(!regs[r]){
+ regs[r]|=4;
+ return r;
+ }
+ }
+ }
+ for(r=1;r<=MAXR;r++){
+ if(ISIDX(r)){
+ if((!(p->q1.flags®)||p->q1.reg!=r)&&
+ (!(p->q2.flags®)||p->q2.reg!=r)&&
+ (!(p->z.flags®)||p->z.reg!=r)){
+ emit(f,"\t%s%s\n",CPU==6812?"psh":"pshs\t",regnames[r]);
+ regs[r]|=8;
+ push(2);
+ return r;
+ }
+ }
+ }
+ ierror(0);
+}
+static int get_reg(FILE *f,struct IC *p,int t)
+{
+ int reg;
+ if(!regs[acc])
+ reg=acc;
+ else if(ISHWORD(t)&&!regs[ix])
+ reg=ix;
+#if 0
+ else if(ISHWORD(t)&&!regs[iy])
+ reg=iy;
+#endif
+ else{
+ get_acc(f,p);
+ reg=acc;
+ }
+ BSET(regs_modified,reg);
+ return reg;
+}
+static void load_reg(FILE *f,int r,struct obj *o,int t)
+{
+ if(!o->am){
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg==r) return;
+ emit(f,"\ttfr\t%s,%s\n",regnames[o->reg],regnames[r]);
+ return;
+ }
+ if(r==acc&&(o->flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&o->val,t);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))){
+ if(CPU!=6812&&!optsize)
+ emit(f,"\tldd\t#0\n");
+ else
+ emit(f,"\tclra\n\tclrb\n");
+ cc=o;cc_t=t;
+ return;
+ }
+ }
+ }
+ if(o->flags&VARADR){
+ char *base=0;
+ if(pcrel&&ISFUNC(o->v->vtyp->flags))
+ base="pc";
+ if(drel&&!ISFUNC(o->v->vtyp->flags))
+ base=regnames[iu];
+ if(base&&!skip_rel){
+ if(ISACC(r))
+ emit(f,"\ttfr\t%s,d\n",base);
+ if(ISIDX(r))
+ emit(f,"\tlea%s\t",regnames[r]);
+ else{
+ if(*base=='p') emit(f,"%s%d:\n",labprefix,++label);
+ emit(f,"\taddd\t#");
+ }
+ emitzm(f,o->val.vmax);
+ emit(f,"+");
+ if(o->v->storage_class==EXTERN)
+ emit(f,"%s%s",idprefix,o->v->identifier);
+ else
+ emit(f,"%s%ld",labprefix,zm2l(o->v->offset));
+ if(ISIDX(r))
+ emit(f,",%s",base);
+ else if(*base=='p')
+ emit(f,"-%s%d",labprefix,label);
+ emit(f,"\n");
+ cc=o;cc_t=t;
+ return;
+ }
+ skip_rel=0;
+ }
+ emit(f,"\tld%s\t",(r==acc&&(t&NQ)==CHAR)?(CPU==6812?"ab":"b"):regnames[r]);
+ emit_obj(f,o,t);emit(f,"\n");
+ cc=o;cc_t=t;
+}
+static void store_reg(FILE *f,int r,struct obj *o,int t)
+{
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg==r) return;
+ emit(f,"\ttfr\t%s,%s\n",regnames[r],regnames[o->reg]);
+ }else{
+ if(r==acc&&(t&NQ)==CHAR)
+ emit(f,"\tst%s\t",(CPU==6812)?"ab":"b");
+ else
+ emit(f,"\tst%s\t",regnames[r]);
+ emit_obj(f,o,t);emit(f,"\n");
+ cc=o;cc_t=t;
+ }
+}
+static void load_addr(FILE *f,int r,struct obj *o)
+{
+ if(o->am){
+ if(o->am->flags==IMM_IND){
+ if(o->am->base==r&&o->am->offset==0&&!o->am->v) return;
+ if(ISIDX(r)){
+ emit(f,"\tlea%s\t",regnames[r]);
+ emit_obj(f,o,0);
+ emit(f,"\n");
+ }else{
+ if(r!=acc) ierror(0);
+ emit(f,"\ttfr\t%s,%s\n",regnames[o->am->base],regnames[r]);
+ emit(f,"\taddd\t#%ld\n",o->am->offset);
+ if(o->am->v){
+ if(o->am->v->storage_class==STATIC)
+ emit(f,"+%s%ld",labprefix,zm2l(o->am->v->offset));
+ else
+ emit(f,"+%s%s",idprefix,o->am->v->identifier);
+ }
+ emit(f,"\n");
+ cc=0;
+ }
+ return;
+ }
+ ierror(0);
+ }
+ if(o->flags&DREFOBJ){
+ o->flags&=~DREFOBJ;
+ load_reg(f,r,o,o->dtyp);
+ o->flags|=DREFOBJ;
+ return;
+ }
+ if((o->flags&(VAR|VARADR))==VAR){
+ if(o->v->storage_class==STATIC||o->v->storage_class==EXTERN){
+ o->flags|=VARADR;
+ load_reg(f,r,o,POINTER_TYPE(o->v->vtyp));
+ o->flags&=~VARADR;
+ return;
+ }
+ if(voff(o)==0){
+ emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[r]);
+ return;
+ }
+ if(ISIDX(r)){
+ emit(f,"\tlea%s\t",regnames[r]);
+ emit_obj(f,o,0);
+ emit(f,"\n");
+ }else{
+ if(r!=acc) ierror(0);
+ emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[r]);
+ emit(f,"\taddd\t#%ld\n",voff(o));
+ cc=0;
+ }
+ return;
+ }
+ ierror(0);
+}
+
+static int scratchreg(int r,struct IC *p)
+{
+ int c;
+ while(1){
+ p=p->next;
+ if(!p||((c=p->code)==FREEREG&&p->q1.reg==r)) return 1;
+ if(c==CALL||(c>=BEQ&&c<=BRA)) return 0;
+ if((p->q1.flags®)&&p->q1.reg==r) return 0;
+ if((p->q2.flags®)&&p->q2.reg==r) return 0;
+ if((p->z.flags®)&&p->z.reg==r) return 0;
+ }
+}
+
+/****************************************/
+/* End of private fata and functions. */
+/****************************************/
+
+
+int init_cg(void)
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+{
+ int i;
+
+ CPU=CPUOPT;
+
+ if (CPU==680912) {
+ bitsperbyte = 12;
+ bytemask = 0xfff;
+ dbl_bytemask = 0xffffff;
+ }
+
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(1L);
+ char_bit=l2zm((long)bitsperbyte);
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+ for(i=1;i<=iu;i++){
+ regsize[i]=l2zm(2L);regtype[i]=&ityp;
+ }
+ regsize[dx]=l2zm(4L);regtype[i]=<yp;
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ if (CPU==680912) {
+ t_min[CHAR]=l2zm(-2048L);
+ t_min[SHORT]=l2zm(-8388608L);
+ t_min[INT]=t_min[SHORT];
+ t_min[LONG]=zmsub(l2zm(0x800000000000LL),l2zm(1L));
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(2047L);
+ t_max[SHORT]=ul2zum(8388607UL);
+ t_max[INT]=t_max[SHORT];
+ t_max[LONG]=ul2zum(0x7fffffffffffULL);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(4095UL);
+ tu_max[SHORT]=ul2zum(16777215UL);
+ tu_max[INT]=tu_max[SHORT];
+ tu_max[LONG]=ul2zum(0xffffffffffffULL);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+ }
+ else {
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=t_min[SHORT];
+ t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=t_max[SHORT];
+ t_max[LONG]=ul2zum(2147483647UL);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=tu_max[SHORT];
+ tu_max[LONG]=ul2zum(4294967295UL);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+ }
+
+ if(g_flags[9]&USEDFLAG) drel=1;
+ if(g_flags[10]&USEDFLAG) MINADDI2P=SHORT;
+ if(g_flags[11]&USEDFLAG) nodx=1;
+ if(g_flags[12]&USEDFLAG) nou=1;
+
+ if(CPU==6812) switchsubs=1;
+
+ /* Reserve a few registers for use by the code-generator. */
+ regsa[sp]=REGSA_NEVER;
+ regscratch[sp]=0;
+
+ if(CPU==6812||drel||nou){
+ regsa[iu]=REGSA_NEVER;
+ regscratch[iu]=0;
+ }
+
+ if(CPU!=6812){
+ regnames[sp]="s";
+ logicals[0]="or";
+ }
+
+ if(!(g_flags[6]&USEDFLAG)){
+ extern int static_cse,dref_cse;
+ static_cse=0;
+ dref_cse=0;
+ }
+
+ if(!(g_flags[7]&USEDFLAG)){
+ regsa[acc]=REGSA_TEMPS;
+ regsa[dx]=REGSA_TEMPS;
+ }
+
+ if(g_flags[8]&USEDFLAG){
+ pcrel=1;
+ jsrinst="lbsr";
+ jmpinst="lbra";
+ rodataname="\t.data\n";
+ }
+
+ if(CPU==6809)
+ marray[1]="__6809__";
+ if(CPU==6309)
+ marray[1]="__6309__";
+ if(CPU==680912)
+ marray[1]="__680912__";
+ target_macros=marray;
+
+
+ declare_builtin("__mulint16",INT,INT,acc,INT,0,1,0);
+ declare_builtin("__divint16",INT,INT,ix,INT,acc,1,0);
+ declare_builtin("__divuint16",UNSIGNED|INT,UNSIGNED|INT,ix,UNSIGNED|INT,acc,1,0);
+ declare_builtin("__modint16",INT,INT,ix,INT,acc,1,0);
+ declare_builtin("__moduint16",UNSIGNED|INT,UNSIGNED|INT,ix,UNSIGNED|INT,acc,1,0);
+
+
+ /* TODO: set argument registers */
+ declare_builtin("__mulint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__addint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__subint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__andint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__orint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__eorint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__negint32",LONG,LONG,0,0,0,1,0);
+ declare_builtin("__lslint32",LONG,LONG,0,INT,0,1,0);
+
+ declare_builtin("__divint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__divuint32",UNSIGNED|LONG,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0);
+ declare_builtin("__modint32",LONG,LONG,0,LONG,0,1,0);
+ declare_builtin("__moduint32",UNSIGNED|LONG,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0);
+ declare_builtin("__lsrsint32",LONG,LONG,0,INT,0,1,0);
+ declare_builtin("__lsruint32",UNSIGNED|LONG,UNSIGNED|LONG,0,INT,0,1,0);
+ declare_builtin("__cmpsint32",INT,LONG,0,LONG,0,1,0);
+ declare_builtin("__cmpuint32",INT,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0);
+ declare_builtin("__sint32toflt32",FLOAT,LONG,0,0,0,1,0);
+ declare_builtin("__uint32toflt32",FLOAT,UNSIGNED|LONG,0,0,0,1,0);
+ declare_builtin("__sint32toflt64",DOUBLE,LONG,0,0,0,1,0);
+ declare_builtin("__uint32toflt64",DOUBLE,UNSIGNED|LONG,0,0,0,1,0);
+ declare_builtin("__flt32tosint32",LONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt32touint32",UNSIGNED|LONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt64tosint32",LONG,DOUBLE,0,0,0,1,0);
+ declare_builtin("__flt64touint32",UNSIGNED|LONG,DOUBLE,0,0,0,1,0);
+
+
+
+ declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
+ declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);
+
+ declare_builtin("__divsint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__modsint64",LLONG,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__lsrsint64",LLONG,LLONG,0,INT,0,1,0);
+ declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
+ declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0);
+ declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
+ declare_builtin("__sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
+ declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
+ declare_builtin("__sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
+ declare_builtin("__uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
+ declare_builtin("__flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
+ declare_builtin("__flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);
+
+ declare_builtin("__flt32toflt64",DOUBLE,FLOAT,0,0,0,1,0);
+ declare_builtin("__flt64toflt32",FLOAT,DOUBLE,0,0,0,1,0);
+
+
+ declare_builtin("__addflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__subflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__mulflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__divflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__negflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
+ declare_builtin("__cmpflt32",INT,FLOAT,0,FLOAT,0,1,0);
+
+ declare_builtin("__addflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__subflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__mulflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__divflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__negflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
+ declare_builtin("__cmpflt64",INT,DOUBLE,0,DOUBLE,0,1,0);
+
+
+ return 1;
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+{
+ int f=t->flags&NQ;
+ if(ISSCALAR(f)){
+ if(ISHWORD(f)||f==CHAR)
+ return acc;
+ else if(ISLWORD(f))
+ return dx;
+ }
+ return 0;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(!ISSCALAR(t)) return 0;
+ if(r==dx){
+ if(ISLWORD(t)&&(optflags&2)&&!nodx) return 1;
+ return 0;
+ }
+ if(mode==-1){
+ if(ISHWORD(t)) return 1;
+ if((t&NQ)==CHAR&&ISACC(r)) return 1;
+ }else{
+ if(ISIDX(r)){
+ if(ISPOINTER(t)&&ISHWORD(t))
+ return 1;
+ }
+ if(ISACC(r)){
+ if((t&NQ)==CHAR)
+ return 1;
+ if(ISINT(t)&&ISHWORD(t))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ if(r==dx){
+ p->r1=acc;
+ p->r2=ix;
+ return 1;
+ }
+ return 0;
+}
+
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+ /*FIXME*/
+ int c=p->code;
+ if(r==dx){
+ if(c==GETRETURN||c==SETRETURN||c==PUSH||c==ASSIGN) return 8;
+ return INT_MIN;
+ }
+ if(o->flags&VKONST){
+ struct obj *co=&o->v->cobj;
+ if(o->flags&DREFOBJ)
+ return 0;
+ if(o==&p->q1&&p->code==ASSIGN&&((p->z.flags&DREFOBJ)||p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)){
+ return 2;
+ }
+ return 0;
+ }
+ if((o->flags&DREFOBJ)){
+ if(!ISIDX(r)) return INT_MIN;
+ if(p->q2.flags&&o!=&p->z)
+ return 6;
+ else
+ return 6;
+ }else if(c==GETRETURN&&p->q1.reg==r){
+ return 4;
+ }else if(c==SETRETURN&&p->z.reg==r){
+ return 4;
+ }else if(c==CONVERT&&((p->typf&NQ)==CHAR||(p->typf2&NQ)==CHAR)&®ok(r,CHAR,0)){
+ return 3;
+ }
+ if(o==&p->z&&r==acc){
+ if(c==SUB||c==SUBIFP||c==SUBPFP||c==AND||c==OR||c==XOR)
+ return 6;
+ if((c==ADD||c==ADDI2P)&&!(p->q1.flags&(KONST|VKONST))&&!(p->q2.flags&(KONST|VKONST)))
+ return 4;
+ if(c==MULT) return 5;
+ if(c==ASSIGN&&(p->q1.flags&KONST)){
+ eval_const(&p->q1.val,p->typf);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL)))
+ return 3;
+ }
+ }
+#if 1
+ if((o==&p->q2/*||o==&p->z*/)&&!(o->flags&DREFOBJ)&&!ISACC(o->reg)&&(c==MULT||c==DIV||c==MOD))
+ return INT_MIN;
+#endif
+ if(c==COMPARE||c==TEST){
+ if(r==ix) return 3;
+ if(r==iy) return 2;
+ if(r==iu) return 1;
+ }
+ return 2;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+/* Return name of library function, if this node should be
+ implemented via libcall. */
+char *use_libcall(int c,int t,int t2)
+{
+ static char fname[16];
+ char *ret=0;
+
+ if(c==COMPARE){
+ if((t&NQ)==LLONG||ISFLOAT(t)){
+ sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }else{
+ t&=NU;
+ t2&=NU;
+ if(t==LDOUBLE) t=DOUBLE;
+ if(t2==LDOUBLE) t2=DOUBLE;
+ if(c==CONVERT){
+ if(t==t2) return 0;
+ if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
+ if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";
+
+ if(ISFLOAT(t)){
+ sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64);
+ ret=fname;
+ }
+ if(ISFLOAT(t2)){
+ sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+ if((t&NQ)==LLONG||ISFLOAT(t)){
+ if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+ if(t==(UNSIGNED|LLONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint64",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==LLONG){
+ sprintf(fname,"__%sint64",ename[c]);
+ ret=fname;
+ }else if(t==(UNSIGNED|LONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint32",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==LONG){
+ sprintf(fname,"__%sint32",ename[c]);
+ ret=fname;
+ }else{
+ sprintf(fname,"__%s%s%s%ld",ename[c],(c!=MULT&&(t&UNSIGNED))?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+ }
+ if((c==MULT&&(CPU==6809||(t&NQ)==LONG))||c==DIV||c==MOD){
+ sprintf(fname,"__%s%s%s%ld",ename[c],(c!=MULT&&(t&UNSIGNED))?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+
+ return ret;
+}
+
+
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+{
+ int op=o&NQ,tp=t&NQ;
+ if(op==tp) return 0;
+ if(ISHWORD(op)&&ISHWORD(tp)) return 0;
+ if(ISFLOAT(op)||ISFLOAT(tp)) return 1;
+ if(ISLWORD(op)&&ISLWORD(tp)) return 0;
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ if(newobj&§ion!=SPECIAL)
+ emit(f,"%ld\n",zm2l(size));
+ else
+ emit(f,"\t.space\t%ld\n",zm2l(size));
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ /* nothing to do */
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(v->tattr&DPAGE)
+ emit(f,"\t.direct\t%s%ld\n",labprefix,zm2l(v->offset));
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&§ion!=DATA){
+ emit(f,dataname);if(f) section=DATA;
+ }
+ if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&§ion!=RODATA){
+ emit(f,rodataname);if(f) section=RODATA;
+ }
+ if(!v->clist&§ion!=BSS){
+ emit(f,bssname);if(f) section=BSS;
+ }
+ }
+ emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset));
+ emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp)));
+ if(v->clist||section==SPECIAL)
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ else
+ emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+ newobj=1;
+ }
+ if(v->storage_class==EXTERN){
+ if(v->flags&(DEFINED|TENTATIVE)){
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ if(v->tattr&DPAGE)
+ emit(f,"\t.direct\t%s%s\n",idprefix,v->identifier);
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&§ion!=DATA){
+ emit(f,dataname);if(f) section=DATA;
+ }
+ if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&§ion!=RODATA){
+ emit(f,rodataname);if(f) section=RODATA;
+ }
+ if(!v->clist&§ion!=BSS){
+ emit(f,bssname);if(f) section=BSS;
+ }
+ }
+ emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
+ emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp)));
+ if(v->clist||section==SPECIAL)
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ else
+ emit(f,"\t.global\t%s%s\n\t.lcomm\t%s%s,",idprefix,v->identifier,idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ emit(f,"\t%s\t",dct[t&NQ]);
+ if(!p->tree){
+ if(ISFLOAT(t)){
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
+ if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE){
+ emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
+ }
+ }else{
+ emitval(f,&p->val,(t&NU)|UNSIGNED);
+ }
+ }else{
+ int m=p->tree->o.flags,md=drel,mp=pcrel;
+ p->tree->o.flags&=~VARADR;
+ drel=0;pcrel=0;
+ emit_obj(f,&p->tree->o,t&NU);
+ p->tree->o.flags=m;
+ drel=md;pcrel=mp;
+ }
+ emit(f,"\n");newobj=0;
+}
+
+
+static void preload(FILE *f,IC *p)
+{
+ int t,r;
+
+ if((p->typf&VOLATILE)||(p->typf2&VOLATILE)||
+ ((p->q1.flags&DREFOBJ)&&(p->q1.dtyp&(VOLATILE|PVOLATILE)))||
+ ((p->q2.flags&DREFOBJ)&&(p->q2.dtyp&(VOLATILE|PVOLATILE)))||
+ ((p->z.flags&DREFOBJ)&&(p->z.dtyp&(VOLATILE|PVOLATILE))))
+ emit(f,"; volatile barrier\n");
+
+ t=q1typ(p);
+ if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){
+ r=get_idx(f,p);
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,r,&p->q1,INT);
+ p->q1.flags|=(REG|DREFOBJ);
+ p->q1.reg=r;
+ }
+ t=q2typ(p);
+ if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){
+ r=get_idx(f,p);
+ p->q2.flags&=~DREFOBJ;
+ load_reg(f,r,&p->q2,INT);
+ p->q2.flags|=(REG|DREFOBJ);
+ p->q2.reg=r;
+ }else if(isreg(z)&&(((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg==p->z.reg)||(p->q2.am&&p->q2.am->base==p->z.reg))){
+ r=get_idx(f,p);
+ p->q2.flags&=~DREFOBJ;
+ load_reg(f,r,&p->q2,INT);
+ p->q2.flags|=(REG|DREFOBJ);
+ p->q2.reg=r;
+ }
+ t=ztyp(p);
+ if(!p->z.am&&(p->z.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){
+ r=get_idx(f,p);
+ p->z .flags&=~DREFOBJ;
+ load_reg(f,r,&p->z ,INT);
+ p->z .flags|=(REG|DREFOBJ);
+ p->z .reg=r;
+ }
+}
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+void gen_code(FILE *f,struct IC *fp,struct Var *v,zmax offset)
+{
+ int c,t,lastcomp=0,reg,short_add,bit_reverse,need_return=0;
+ struct obj *bit_obj;char *bit_reg;
+ static int idone;
+ struct obj o;
+ IC *p,*p2;
+ if(v->tattr&INTERRUPT)
+ ret="rti";
+ else if (v->tattr&FAR)
+ ret="rtf";
+ else
+ ret="rts"; /*FIXME: banked */
+ if(DEBUG&1) printf("gen_code()\n");
+ for(p=fp;p;p=p->next) clear_ext_ic(&p->ext);
+ emit(f,"#off1=%ld\n",zm2l(offset));
+ if(!(g_flags[5]&USEDFLAG)){
+ peephole(fp);
+ if(!frame_used) offset=l2zm(0L);
+ }
+ for(c=1;c<=MAXR;c++) regs[c]=(regsa[c]==REGSA_NEVER)?1:0;
+ for(c=1;c<=MAXR;c++){
+ if(regscratch[c]&&(regsa[c]||regused[c])){
+ BSET(regs_modified,c);
+ }
+ }
+ t=0;
+ for(p=fp;p;p=p->next){
+ c=p->code;
+ if(c==ALLOCREG){ regs[p->q1.reg]=1; if(p->q1.reg==dx) regs[acc]=regs[ix]=1;}
+ if(c==FREEREG){ regs[p->q1.reg]=0; if(p->q1.reg==dx) regs[acc]=regs[ix]=0;}
+ if((c==LSHIFT||c==RSHIFT)&&(p->typf&NQ)>=LONG) regused[iy]=1;
+ if(c==PUSH&&(p->q1.flags&(REG|DREFOBJ))!=REG){
+ if(zmeqto(p->q2.val.vmax,Z1)){
+ if(regs[acc]) t=(t>2)?t:2;
+ }else if(zmeqto(p->q2.val.vmax,l2zm(2L))){
+ if(regs[acc]&®s[ix]&®s[iy]&&(CPU==6812||regs[iu])) t=(t>2)?t:2;
+ }else if(zmeqto(p->q2.val.vmax,l2zm(4L))){
+ if(regs[acc]) t=(t>2)?t:2;
+ }else{
+ /* TODO: finer check */
+ if(drel||!regsa[iu])
+ t=(t>8)?t:8;
+ else
+ t=(t>6)?t:6;
+ }
+ }
+ }
+ emit(f,"#toff=%d\n",t);
+ loff=zm2l(offset)+t;
+ function_top(f,v,loff);
+ stackoffset=notpopped=dontpop=maxpushed=0;
+ for(p=fp;p;pr(f,p),p=p->next){
+ c=p->code;t=p->typf;
+ if(debug_info)
+ dwarf2_line_info(f,p);
+ short_add=0;
+ if(c==NOP) continue;
+ if(c==ALLOCREG){
+ regs[p->q1.reg]=1;
+ if(p->q1.reg==dx) regs[acc]=regs[ix]=1;
+ continue;
+ }
+ if(c==FREEREG){
+ regs[p->q1.reg]=0;
+ if(p->q1.reg==dx) regs[acc]=regs[ix]=0;
+ continue;
+ }
+ if(notpopped&&!dontpop){
+ int flag=0;
+ if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+ gen_pop(f,notpopped);
+ notpopped=0;
+ }
+ }
+ if(c==LABEL) {cc=0;emit(f,"%s%d:\n",labprefix,t);continue;}
+ if(c>=BEQ&&c<=BGT&&t==exit_label) need_return=1;
+ if(c==BRA){
+ if(p->typf==exit_label&&!have_frame){
+ emit(f,"\t%s\n",ret);
+ }else{
+ if(t==exit_label) need_return=1;
+ emit(f,"\tbra\t%s%d\n",labprefix,t);
+ }
+ cc=0;continue;
+ }
+ if(c>=BEQ&&c<BRA){
+ if((lastcomp&UNSIGNED)||ISPOINTER(lastcomp))
+ emit(f,"\tb%s\t%s%d\n",uccs[c-BEQ],labprefix,t);
+ else
+ emit(f,"\tb%s\t%s%d\n",ccs[c-BEQ],labprefix,t);
+ continue;
+ }
+ if(c==MOVETOREG){
+ load_reg(f,p->z.reg,&p->q1,SHORT);
+ continue;
+ }
+ if(c==MOVEFROMREG){
+ store_reg(f,p->q1.reg,&p->z,SHORT);
+ continue;
+ }
+
+ /*if(ISFLOAT(t)) {pric2(stdout,p);ierror(0);}*/
+
+ if((t&NQ)==BIT){
+ ierror(0);
+ }
+
+ if(c==CONVERT&&ISLWORD(t)&&ISLWORD(p->typf2)){
+ p->code=c=ASSIGN;
+ p->q2.val.vmax=l2zm(4L);
+ }
+
+ if((p->q2.flags®)&&ISACC(p->q2.reg)&&(c==ADD||c==MULT||c==AND||c==OR||c==XOR)){
+ obj o=p->q1;
+ p->q1=p->q2;
+ p->q2=o;
+ }
+
+ if(c==TEST){
+ lastcomp=t;
+ p->code=c=COMPARE;
+ gval.vmax=l2zm(0L);
+ p->q2.flags=KONST;
+ eval_const(&gval,MAXINT);
+ insert_const(&p->q2.val,t);
+ }
+
+ if(c==SUBPFP){
+ p->code=c=SUB;
+ p->typf=t=(UNSIGNED|INT);
+ }
+
+
+
+ if((c==ASSIGN||c==PUSH)&&zmeqto(p->q2.val.vmax,l2zm(4L)))
+ p->typf=t=LONG;
+
+ preload(f,p);
+
+ if(c==ADDI2P||c==SUBIFP){
+ if((p->typf2&NQ)!=HPOINTER){
+ if(p->q2.flags&KONST){
+ eval_const(&p->q2.val,p->typf);
+ insert_const(&p->q2.val,p->typf2);
+ p->typf=t=(UNSIGNED|SHORT);
+ }else{
+ if(ISLWORD(t)) inc_addr(&p->q2,2,t);
+ if((t&NQ)==CHAR) short_add=t;
+ p->typf=t=(UNSIGNED|SHORT);
+ }
+ }else if(ISHWORD(t)){
+ if((t&NQ)==LLONG)
+ inc_addr(&p->q2,4,t);
+ else if((t&NQ)!=LONG)
+ short_add=t;
+ p->typf=t=(UNSIGNED|LONG);
+ }
+ p->code=c=(c==ADDI2P)?ADD:SUB;
+ }
+
+ if(c==COMPARE&&ISLWORD(t)){
+ IC *branch=p->next;
+ int r;
+ while(branch&&branch->code==FREEREG) branch=branch->next;
+ if(!branch) ierror(0);
+ c=branch->code;
+ if(c<BEQ||c>BGT) ierror(0);
+ if(!regs[ix])
+ r=ix;
+ else
+ r=get_reg(f,p,INT);
+
+ if(c==BEQ||c==BNE){
+ inc_addr(&p->q1,0,t);
+ inc_addr(&p->q2,0,t);
+ load_reg(f,r,&p->q1,INT);
+ emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+ emit_obj(f,&p->q2,INT);
+ emit(f,"\n");
+ if(pushed_acc) emit(f,SPULLD);
+ emit(f,"\tbne\t%s%d\n",labprefix,c==BEQ?++label:branch->typf);
+ if(pushed_acc) emit(f,SPUSHD);
+ inc_addr(&p->q1,2,t);
+ inc_addr(&p->q2,2,t);
+ load_reg(f,r,&p->q1,INT);
+ emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+ emit_obj(f,&p->q2,INT);
+ emit(f,"\n");
+ pr(f,p);
+ if(c==BEQ){
+ emit(f,"\tbeq\t%s%d\n",labprefix,branch->typf);
+ emit(f,"%s%d:\n",labprefix,label);
+ }else
+ emit(f,"\tbne\t%s%d\n",labprefix,branch->typf);
+ }else{
+ inc_addr(&p->q1,0,t);
+ inc_addr(&p->q2,0,t);
+ load_reg(f,r,&p->q1,INT);
+ emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+ emit_obj(f,&p->q2,INT);
+ emit(f,"\n");
+ label++;
+ if(pushed_acc) emit(f,SPULLD);
+ if(t&UNSIGNED){
+ if(c==BLT||c==BGT)
+ emit(f,"\tb%s\t%s%d\n",(c==BLT)?"lo":"hi",labprefix,branch->typf);
+ else
+ emit(f,"\tb%s\t%s%d\n",(c==BGE)?"lo":"hi",labprefix,label);
+ }else{
+ if(c==BLT||c==BGT)
+ emit(f,"\tb%s\t%s%d\n",(c==BLT)?"lt":"gt",labprefix,branch->typf);
+ else
+ emit(f,"\tb%s\t%s%d\n",(c==BGE)?"lt":"gt",labprefix,label);
+ }
+ emit(f,"\tbne\t%s%d\n",labprefix,(c==BLT||c==BGT)?label:branch->typf);
+ if(pushed_acc) emit(f,SPUSHD);
+ inc_addr(&p->q1,2,t);
+ inc_addr(&p->q2,2,t);
+ load_reg(f,r,&p->q1,INT);
+ emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
+ emit_obj(f,&p->q2,INT);
+ emit(f,"\n");
+ pr(f,p);
+ emit(f,"\tb%s\t%s%d\n",uccs[c-BEQ],labprefix,branch->typf);
+ emit(f,"%s%d:\n",labprefix,label);
+ }
+ branch->code=NOP;
+ continue;
+ }
+
+ if(ISLWORD(t)&&(c==LSHIFT||c==RSHIFT)){
+ int cnt=-1000,i,r=0;
+ int px=0,py=0,pa=0;
+ if(isconst(q2)){
+ eval_const(&p->q2.val,p->typf2);
+ cnt=(int)zm2l(vmax);
+ if(cnt==1&&compare_objects(&p->q1,&p->z)){
+ if(c==LSHIFT)
+ emit(f,"\tlsl\t");
+ else
+ emit(f,"\t%s\t",(t&UNSIGNED)?"lsr":"asr");
+ inc_addr(&p->z,c==LSHIFT?3:0,t);
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror");
+ inc_addr(&p->z,c==LSHIFT?-1:1,t);
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror");
+ inc_addr(&p->z,c==LSHIFT?-1:1,t);
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror");
+ inc_addr(&p->z,c==LSHIFT?-1:1,t);
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ continue;
+ }
+ }
+ inc_addr(&p->q1,2,t);
+ inc_addr(&p->z,2,t);
+
+ if(ISRACC(q2)||(regs[acc]&&!scratchreg(acc,p))){
+ emit(f,SPUSHD);
+ push(2);
+ pa=1;
+ }
+
+ if(cnt<0||(optsize&&cnt>1)||(cnt>3&&!optspeed)){
+ if(regs[ix]&&!scratchreg(ix,p)) {px=1;emit(f,SPUSH("x"));push(2);}
+ if(regs[iy]&&!scratchreg(iy,p)) {py=1;emit(f,SPUSH("y"));push(2);}
+ }
+
+ if(!compare_objects(&p->q1,&p->z)){
+ load_reg(f,acc,&p->q1,INT);
+ store_reg(f,acc,&p->z,INT);
+ }
+ inc_addr(&p->q1,-2,t);
+ inc_addr(&p->z,-2,t);
+ load_reg(f,acc,&p->q1,INT);
+ if(cnt<0||(optsize&&cnt>1)||(cnt>3&&!optspeed)){
+ if((p->q2.flags®)&&p->q2.reg==ix){
+ if((p->z.flags®)&&p->z.reg==iy) ierror(0);
+ }else
+ load_addr(f,ix,&p->z);
+ if(ISRACC(q2)){
+ if(scratchreg(acc,p)&&(px+py==0)){
+ emit(f,SPULL("y"));
+ pop(2);pa=0;
+ }else
+ emit(f,"\tldy\t%d,%s\n",(px+py)*2,regnames[sp]);
+ }else
+ load_reg(f,iy,&p->q2,p->typf2); /*TODO: types!=INT?? */
+ if((p->q2.flags®)&&p->q2.reg==ix)
+ load_addr(f,ix,&p->z);
+ if(c==LSHIFT)
+ emit(f,"\t%s\t%s__lsll\n",jsrinst,idprefix);
+ else
+ emit(f,"\t%s\t%s__%s\n",jsrinst,idprefix,(t&UNSIGNED)?"lsrl":"asrl");
+ if(py) {emit(f,SPULL("y"));pop(2);}
+ if(px) {emit(f,SPULL("x"));pop(2);}
+ }else{
+ inc_addr(&p->z,c==LSHIFT?3:2,t);
+ for(i=0;i<cnt;i++){
+ if(c==LSHIFT){
+ emit(f,"\tlsl\t");
+ emit_obj(f,&p->z,CHAR);
+ emit(f,"\n");
+ inc_addr(&p->z,-1,t);
+ emit(f,"\trol\t");
+ emit_obj(f,&p->z,CHAR);
+ emit(f,"\n");
+ inc_addr(&p->z,1,t);
+ emit(f,"\trolb\n");
+ emit(f,"\trola\n");
+ }else{
+ emit(f,"\t%s\n",(t&UNSIGNED)?"lsra":"asra");
+ emit(f,"\trorb\n");
+ emit(f,"\tror\t");
+ emit_obj(f,&p->z,CHAR);
+ emit(f,"\n");
+ inc_addr(&p->z,1,t);
+ emit(f,"\tror\t");
+ emit_obj(f,&p->z,CHAR);
+ emit(f,"\n");
+ inc_addr(&p->z,-1,t);
+ }
+ }
+ inc_addr(&p->z,c==LSHIFT?-3:-2,t);
+ store_reg(f,acc,&p->z,INT);
+ }
+ if(pa) {emit(f,SPULLD);pop(2);}
+ continue;
+ }
+
+ if(ISLWORD(t)&&c!=GETRETURN&&c!=SETRETURN&&c!=COMPARE&&c!=CONVERT&&c!=ADDRESS){
+ if(c==PUSH&&isreg(q1)&&p->q1.reg==dx){
+ if(CPU==6812){
+ emit(f,"\tpshd\n");
+ emit(f,"\tpshx\n");
+ }else{
+ //emit(f,"\tpshs\ta,b,x\n");
+ emit(f,"\tpshs\tb,a\n");
+ emit(f,"\tpshs\tx\n");
+ }
+ push(4);
+ continue;
+ }
+ if(c==ASSIGN&&isreg(q1)&&p->q1.reg==dx){
+ inc_addr(&p->z,2,t);
+ store_reg(f,ix,&p->z,INT);
+ inc_addr(&p->z,-2,t);
+ store_reg(f,acc,&p->z,INT);
+ continue;
+ }
+ if(c==ASSIGN&&isreg(z)&&p->z.reg==dx){
+ inc_addr(&p->q1,2,t);
+ load_reg(f,ix,&p->q1,INT);
+ inc_addr(&p->q1,-2,t);
+ load_reg(f,acc,&p->q1,INT);
+ continue;
+ }
+ if(c==PUSH){
+ if(regs[acc]) emit(f,"\tstd\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+ }else
+ get_acc(f,p);
+ /*TODO: acc in IC, constants */
+ inc_addr(&p->q1,2,t);
+ if(c==MINUS){
+ if(CPU!=6812&&!optsize)
+ emit(f,"\tldd\t#0\n");
+ else
+ emit(f,"\tclra\n\tclrb\n");
+ }else
+ load_reg(f,acc,&p->q1,INT);
+ if(c==ADD||c==SUB){
+ inc_addr(&p->q2,2,t);
+ emit(f,"\t%s\t",c==ADD?"addd":"subd");
+ emit_obj(f,&p->q2,INT);
+ emit(f,"\n");
+ }else if(c==ASSIGN||c==PUSH){
+ }else if(c==MINUS){
+ emit(f,"\tsubd\t");
+ emit_obj(f,&p->q1,INT);
+ emit(f,"\n");
+ }else if(c==KOMPLEMENT){
+ emit(f,"\tcoma\n");
+ emit(f,"\tcomb\n");
+ }else{
+ if(c==AND)
+ emit(f,"\tandb\t");
+ else if(c==OR)
+ emit(f,"\tor%sb\t",CPU==6812?"a":"");
+ else if(c==XOR)
+ emit(f,"\teorb\t");
+ inc_addr(&p->q2,3,t);
+ emit_obj(f,&p->q2,CHAR);
+ emit(f,"\n");
+ if(c==AND)
+ emit(f,"\tanda\t");
+ else if(c==OR)
+ emit(f,"\tor%sa\t",CPU==6812?"a":"");
+ else if(c==XOR)
+ emit(f,"\teora\t");
+ inc_addr(&p->q2,-1,t);
+ emit_obj(f,&p->q2,CHAR);
+ emit(f,"\n");
+ }
+ if(c==PUSH){
+ if(CPU==6812)
+ emit(f,"\tpshd\n");
+ else
+ emit(f,"\tpshs\tb,a\n");
+ push(2);dontpop+=2;
+ }else{
+ inc_addr(&p->z,2,t);
+ store_reg(f,acc,&p->z,INT);
+ }
+ inc_addr(&p->q1,-2,t);
+ if(c==MINUS)
+ emit(f,"\tldd\t#0\n");
+ else
+ load_reg(f,acc,&p->q1,INT);
+ if(c==ADD)
+ emit(f,"\tadcb\t");
+ else if(c==SUB)
+ emit(f,"\tsbcb\t");
+ else if(c==AND)
+ emit(f,"\tandb\t");
+ else if(c==OR)
+ emit(f,"\tor%sb\t",CPU==6812?"a":"");
+ else if(c==XOR)
+ emit(f,"\teorb\t");
+ else if(c==KOMPLEMENT)
+ emit(f,"\tcomb\n");
+ else if(c==MINUS){
+ inc_addr(&p->q1,1,t);
+ emit(f,"\tsbcb\t");
+ emit_obj(f,&p->q1,CHAR);
+ emit(f,"\n");
+ }
+ if(p->q2.flags){
+ inc_addr(&p->q2,-1,t);
+ emit_obj(f,&p->q2,CHAR);
+ emit(f,"\n");
+ }
+ if(c==ADD)
+ emit(f,"\tadca\t");
+ else if(c==SUB)
+ emit(f,"\tsbca\t");
+ else if(c==AND)
+ emit(f,"\tanda\t");
+ else if(c==OR)
+ emit(f,"\tor%sa\t",CPU==6812?"a":"");
+ else if(c==XOR)
+ emit(f,"\teora\t");
+ else if(c==KOMPLEMENT)
+ emit(f,"\tcoma\n");
+ else if(c==MINUS){
+ inc_addr(&p->q1,-1,t);
+ emit(f,"\tsbca\t");
+ emit_obj(f,&p->q1,CHAR);
+ emit(f,"\n");
+ }
+ if(p->q2.flags){
+ inc_addr(&p->q2,-1,t);
+ emit_obj(f,&p->q2,CHAR);
+ emit(f,"\n");
+ }
+ if(c==PUSH){
+ if(CPU==6812)
+ emit(f,"\tpshd\n");
+ else
+ emit(f,"\tpshs\tb,a\n");
+ push(2);dontpop+=2;
+ if(regs[acc]) emit(f,"\tldd\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+ }else{
+ inc_addr(&p->z,-2,t);
+ store_reg(f,acc,&p->z,INT);
+ }
+ continue;
+ }
+
+
+ if(c==COMPARE){
+ int vadr;
+ if(drel&&(p->q1.flags&VARADR)&&!ISFUNC(p->q1.v->vtyp->flags)) vadr=1;
+ else if(drel&&(p->q2.flags&VARADR)&&!ISFUNC(p->q2.v->vtyp->flags)) vadr=2;
+ else if(pcrel&&(p->q1.flags&VARADR)&&ISFUNC(p->q1.v->vtyp->flags)) vadr=1;
+ else if(pcrel&&(p->q2.flags&VARADR)&&ISFUNC(p->q2.v->vtyp->flags)) vadr=2;
+ else vadr=0;
+ if(vadr!=1&&(vadr==2||isconst(q1)||ISRACC(q2))){
+ struct IC *p2;
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ p2=p->next;
+ while(p2&&p2->code==FREEREG) p2=p2->next;
+ if(!p2||p2->code<BEQ||p2->code>BGT) ierror(0);
+ if(p2->code==BLT) p2->code=BGT;
+ else if(p2->code==BGT) p2->code=BLT;
+ else if(p2->code==BLE) p2->code=BGE;
+ else if(p2->code==BGE) p2->code=BLE;
+ }
+ /* case with two relative addresses */
+ if(drel&&(p->q2.flags&VARADR)&&!ISFUNC(p->q2.v->vtyp->flags)) skip_rel=1;
+ if(pcrel&&(p->q2.flags&VARADR)&&ISFUNC(p->q2.v->vtyp->flags)) skip_rel=1;
+ }
+#if 0
+ /* TODO: fix cc */
+ if(c==COMPARE&&isconst(q2)){
+ eval_const(&p->q2.val,t);
+ if(ISNULL()){
+ if(cc&&(cc_t&NU)==(t&NU)&&compare_objects(cc,&p->q1)){
+ lastcomp=t;continue;
+ }
+ }
+ }
+#endif
+
+ if(!short_add)
+ switch_IC(p);
+
+ if(c==CONVERT){
+ int to=p->typf2&NU;
+ if(to==INT) to=SHORT;
+ if(to==(UNSIGNED|INT)||to==NPOINTER) to=(UNSIGNED|SHORT);
+ if(to==FPOINTER||to==HPOINTER) to=(UNSIGNED|LONG);
+ if((t&NU)==INT) t=SHORT;
+ if((t&NU)==(UNSIGNED|INT)||(t&NU)==NPOINTER) t=(UNSIGNED|SHORT);
+ if((t&NQ)==FPOINTER||(t&NQ)==HPOINTER) t=(UNSIGNED|LONG);
+ /*if((t&NQ)>=LONG||(to&NQ)>=LONG) ierror(0);*/
+ if((to&NQ)<=LONG&&(t&NQ)<=LONG){
+ if((to&NQ)<(t&NQ)){
+ if(ISLWORD(t)){
+ get_acc(f,p);
+ load_reg(f,acc,&p->q1,to);
+ if((to&NU)==CHAR)
+ emit(f,SEX);
+ else if((to&NU)==(UNSIGNED|CHAR))
+ emit(f,"\tclra\n");
+ inc_addr(&p->z,2,t);
+ store_reg(f,acc,&p->z,INT);
+ inc_addr(&p->z,-2,t);
+ if(to&UNSIGNED){
+ emit(f,"\tclra\n\tclrb\n");
+ }else{
+ if(CPU==6812)
+ emit(f,"\texg\ta,b\n");
+ else
+ emit(f,"\ttfr\ta,b\n");
+ emit(f,SEX);
+ emit(f,"\ttfr\ta,b\n");
+ }
+ store_reg(f,acc,&p->z,INT);
+ continue;
+ }
+ /*emit(f,"#conv RACC=%d, regs=%d scratch=%d\n",(int)ISRACC(z),regs[acc],scratchreg(acc,p));*/
+ if(!ISRACC(z))
+ get_acc(f,p);
+ load_reg(f,acc,&p->q1,to);
+ if(to&UNSIGNED)
+ emit(f,"\tclra\n");
+ else
+ emit(f,SEX);
+ store_reg(f,acc,&p->z,t);
+ cc=&p->z;cc_t=t;
+ continue;
+ }else if((to&NQ)>(t&NQ)){
+ if(!ISRACC(z)&&!ISRACC(q1))
+ get_acc(f,p);
+ if(ISLWORD(to))
+ inc_addr(&p->q1,2,to);
+ load_reg(f,acc,&p->q1,to);
+ store_reg(f,acc,&p->z,t);
+ continue;
+ }else{
+ c=ASSIGN;
+ p->q2.val.vmax=sizetab[t&NQ];
+ }
+ }
+ }
+ if(c==KOMPLEMENT){
+ cc=0;
+ if(compare_objects(&p->q1,&p->z)&&!isreg(q1)&&(p->q1.flags&(REG|DREFOBJ))!=DREFOBJ&&(!p->q1.am||p->q1.am->flags!=ACC_IND)){
+ emit(f,"\tcom\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ if(ISHWORD(t)){
+ mobj=p->z;
+ inc_addr(&mobj,1,t);
+ emit(f,"\tcom\t");
+ emit_obj(f,&mobj,INT);
+ emit(f,"\n");
+ }
+ continue;
+ }
+ if((!isreg(z)||p->z.reg!=acc)&®s[acc]&&!scratchreg(acc,p))
+ get_acc(f,p);
+ load_reg(f,acc,&p->q1,t);
+ emit(f,"\tcoma\n\tcomb\n");
+ store_reg(f,acc,&p->z,t);
+ continue;
+ }
+ if(c==MINUS){
+ if((!isreg(z)||p->z.reg!=acc)&®s[acc]&&!scratchreg(acc,p))
+ get_acc(f,p);
+ if(isreg(q1)){
+ load_reg(f,acc,&p->q1,t);
+ emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+ }else{
+ if(CPU!=6812&&!optsize)
+ emit(f,"\tldd\t#0\n");
+ else
+ emit(f,"\tclra\n\tclrb\n");
+ emit(f,"\tsubd\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ cc=&p->z;cc_t=t;
+ store_reg(f,acc,&p->z,t);
+ continue;
+ }
+ if(c==SETRETURN){
+ if(isreg(q1)&&p->q1.reg==p->z.reg) continue;
+ if(p->z.reg){
+ if(ISLWORD(t)){
+ inc_addr(&p->q1,0,t);
+ load_reg(f,ix,&p->q1,INT);
+ BSET(regs_modified,ix);
+ inc_addr(&p->q1,2,t);
+ }
+ load_reg(f,acc,&p->q1,t);
+ BSET(regs_modified,acc);
+
+ }
+ continue;
+ }
+ if(c==GETRETURN){
+ if(isreg(z)&&p->z.reg==p->q1.reg) continue;
+ if(p->q1.reg){
+ if(ISLWORD(t)){
+ store_reg(f,ix,&p->z,INT);
+ BSET(regs_modified,ix);
+ inc_addr(&p->z,2,t);
+ }
+ store_reg(f,acc,&p->z,(t&NQ)==CHAR?t:INT);
+ }
+ continue;
+ }
+ if(c==CALL){
+ int reg,jmp=0;
+ cc=0;
+ if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS;
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+ long of=va_offset(v)+loff+2;
+ emit(f,"\ttfr\t%s,d\n",regnames[sp]);
+ if(of) emit(f,"\taddd\t#%ld\n",of);
+ continue;
+ }
+ if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ jmp=1;
+ }else{
+ if(stackoffset==0&&!have_frame&&!strcmp(ret,"rts")){
+ struct IC *p2;
+ jmp=1;
+ for(p2=p->next;p2;p2=p2->next){
+ if(p2->code!=FREEREG&&p2->code!=ALLOCREG&&p2->code!=LABEL){
+ jmp=0;break;
+ }
+ }
+ }
+ if(p->q1.flags&DREFOBJ){
+ /*FIXME: test this*/
+ if(jmp)
+ emit(f,"\tjmp\t");
+ else
+ emit(f,"\tjsr\t");
+ if (p->q1.v->tattr&FAR)
+ emit(f,"\tfar\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }else{
+ if(jmp){
+ emit(f,"\t%s\t",jmpinst); /*emit(f,"\tbra\t");*/
+ /*if(!need_return) ret=0;*/ /*TODO: works with optimizer? */
+ }else{
+ emit(f,"\t%s\t",jsrinst); /*emit(f,"\tbsr\t");*/
+ }
+ if (p->q1.v->tattr&FAR)
+ emit(f,"\tfar\t");
+ if(pcrel){
+ pcrel=0;
+ emit_obj(f,&p->q1,t);
+ pcrel=1;
+ }else
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ }
+ if(stack_valid){
+ int i;
+ if(p->call_cnt<=0){
+ err_ic=p;if(f) error(320);
+ stack_valid=0;
+ }
+ for(i=0;stack_valid&&i<p->call_cnt;i++){
+ if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_STACK)){
+ /*FIXME: size of return addr depends on mode */
+ if(!jmp) push(2);
+ callee_push(zm2l(p->call_list[i].v->fi->stack1));
+ if(!jmp) pop(2);
+ }else{
+ err_ic=p;if(f) error(317,p->call_list[i].v->identifier);
+ stack_valid=0;
+ }
+ }
+ }
+ if(!zmeqto(l2zm(0L),p->q2.val.vmax)){
+ notpopped+=zm2l(p->q2.val.vmax);
+ dontpop-=zm2l(p->q2.val.vmax);
+ if(!(g_flags[2]&USEDFLAG)&&stackoffset==-notpopped){
+ /* Entfernen der Parameter verzoegern */
+ }else{
+ gen_pop(f,zm2l(p->q2.val.vmax));
+ notpopped-=zm2l(p->q2.val.vmax);
+ }
+ }
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax);
+ if(!zmleq(p->q2.val.vmax,l2zm(2L))){
+ unsigned long size;int qr=0,zr=0,cr=0,px=0,py=0,pu=0,pd=0,lq=0,lz=0;
+ size=zm2l(p->q2.val.vmax);
+ if(c==ASSIGN){
+ if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ISIDX(p->z.reg)){
+ zr=p->z.reg;lz=1;
+ }
+ }
+ if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ISIDX(p->q1.reg)&&p->q1.reg!=zr){
+ qr=p->q1.reg;lq=1;
+ }
+ if(!qr){
+ if(zr==ix) qr=iy;
+ else if(zr==iy||zr==iu) qr=ix;
+ else{qr=ix;zr=iy;}
+ }else if(!zr){
+ if(qr==ix) zr=iy; else zr=ix;
+ }
+ if(CPU!=6812){
+ if(qr!=iu&&zr!=iu) cr=iu;
+ if(qr!=ix&&zr!=ix) cr=ix;
+ if(qr!=iy&&zr!=iy) cr=iy;
+ if(!cr) ierror(0);
+ }
+ if(c==PUSH){
+ emit(f,"\tleas\t%ld,%s\n",SGN16(-size),regnames[sp]);
+ push(size);
+ }
+ if(CPU!=6812&&(drel||!regused[iu]||(regs[iu]&&!scratchreg(iu,p)))){
+ if(c==PUSH)
+ emit(f,"\tstu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
+ else{
+ emit(f,SPUSH("u"));
+ push(2);
+ }
+ pu=1;
+ }
+ if(!regused[iy]||(regs[iy]&&!scratchreg(iy,p))){
+ if(c==PUSH)
+ emit(f,"\tsty\t%ld,%s\n",loff-roff-4-stackoffset,regnames[sp]);
+ else{
+ emit(f,SPUSH("y"));
+ push(2);
+ }
+ py=1;
+ }
+ if(regs[ix]&&!scratchreg(ix,p)){
+ if(c==PUSH)
+ emit(f,"\tstx\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+ else{
+ emit(f,SPUSH("x"));
+ push(2);
+ }
+ px=1;
+ }
+ if(!lq) load_addr(f,qr,&p->q1);
+ if(c==PUSH)
+ emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[zr]);
+ else
+ if(!lz) load_addr(f,zr,&p->z);
+ if(size<=6||(size<=16&&!optsize)){
+ if(CPU!=6812){
+ if(!scratchreg(acc,p)){
+ if(c==PUSH)
+ emit(f,"\tstd\t%ld,%s\n",loff-roff-6-stackoffset,regnames[sp]);
+ else{
+ emit(f,SPUSHD);
+ push(2);
+ }
+ pd=2;
+ }
+ }
+ while(size>2){
+ if(CPU==6812)
+ emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+ else
+ emit(f,"\tldd\t,%s++\n\tstd\t,%s++\n",regnames[qr],regnames[zr]);
+ size-=2;
+ }
+ if(CPU==6812)
+ emit(f,"\tmov%c\t0,%s,0,%s\n",size==2?'w':'b',regnames[qr],regnames[zr]);
+ else
+ emit(f,"\tld%c\t,%s\n\tst%c\t,%s\n",size==2?'d':'b',regnames[qr],size==2?'d':'b',regnames[zr]);
+ }else{
+ int l=++label,cnt=(int)(optsize?size:size/8);
+ if(regs[acc]&&!scratchreg(acc,p)){
+ if(c==PUSH)
+ emit(f,"\tst%c\t%ld,%s\n",(CPU!=6812&&cnt<=bytemask)?'b':'d',loff-roff-6-stackoffset,regnames[sp]);
+ else{
+ if(CPU!=6812&&cnt<=bytemask){
+ emit(f,SPUSH("b"));
+ push(1);
+ }else{
+ emit(f,SPUSHD);
+ push(2);
+ }
+ }
+ pd=(CPU!=6812&&cnt<=bytemask)?1:2;
+ }
+ if(CPU!=6812&&cnt<=bytemask)
+ emit(f,"\tldb\t#%lu\n",cnt);
+ else
+ emit(f,"\tldd\t#%lu\n",cnt);
+ cc=0;
+#if 0
+ if(CPU!=6812&&((!regsa[iu]&®s[iu])||drel)){
+ if(c==PUSH){
+ emit(f,"\tstu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
+ }else{
+ emit(f,SPUSH("u"));push(2);
+ }
+ }
+#endif
+ emit(f,"%s%d:\n",labprefix,l);
+ if(CPU==6812){
+ if(optsize){
+ emit(f,"\tmovb\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+ }else{
+ emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+ emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+ emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+ emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+ size=size&7;
+ }
+ emit(f,"\tdbne\td,%s%d\n",labprefix,l);
+ }else{
+ if(optsize){
+ emit(f,"\tld%s\t,%s+\n\tst%s\t,%s+\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+ size&=1;
+ }else{
+ emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+ emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+ emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+ emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
+ size&=7;
+ }
+ if(cnt<=bytemask)
+ emit(f,"\tdecb\n");
+ else
+ emit(f,"\tsubd\t#1\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,l);
+ }
+#if 0
+ if(CPU!=6812&&((!regsa[iu]&®s[iu])||drel)){
+ if(c==PUSH){
+ emit(f,"\tldu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
+ }else{
+ emit(f,SPULL("u"));pop(2);
+ }
+ }
+#endif
+ while(size>=2){
+ if(CPU==6812)
+ emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
+ else
+ emit(f,"\tldd\t,%s++\n\tstd\t,%s++\n",regnames[qr],regnames[zr]);
+ size-=2;
+ }
+ if(size){
+ if(CPU==6812)
+ emit(f,"\tmovb\t0,%s,0,%s\n",regnames[qr],regnames[zr]);
+ else
+ emit(f,"\tldb\t,%s\n\tstb\t,%s\n",regnames[qr],regnames[zr]);
+ }
+ }
+ if(pd){
+ if(c==PUSH)
+ emit(f,"\tld%c\t%ld,%s\n",(pd==1)?'b':'d',loff-roff-6-stackoffset,regnames[sp]);
+ else{
+ if(pd==1){
+ emit(f,SPULL("b"));
+ pop(1);
+ }else{
+ emit(f,SPULLD);
+ pop(2);
+ }
+ }
+ }
+ if(px){
+ if(c==PUSH)
+ emit(f,"\tldx\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
+ else{
+ emit(f,SPULL("x"));
+ pop(2);
+ }
+ }
+ if(py){
+ if(c==PUSH)
+ emit(f,"\tldy\t%ld,%s\n",loff-roff-4-stackoffset,regnames[sp]);
+ else{
+ emit(f,SPULL("y"));
+ pop(2);
+ }
+ }
+ if(pu){
+ if(c==PUSH)
+ emit(f,"\tldu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
+ else{
+ emit(f,SPULL("u"));
+ pop(2);
+ }
+ }
+ continue;
+ }
+ if(!ISSCALAR(t)) t=zmeqto(p->q2.val.vmax,l2zm(1L))?CHAR:INT;
+ if((t&NQ)==CHAR&&!zmeqto(p->q2.val.vmax,l2zm(1L))) t=INT;
+ if(mov_op(&p->q1)&&(c==PUSH||mov_op(&p->z))){
+ emit(f,"\tmov%c\t",ISHWORD(t)?'w':'b');
+ emit_obj(f,&p->q1,t);
+ if(c==ASSIGN){
+ emit(f,",");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ }else{
+ emit(f,",%d,-%s\n",ISHWORD(t)?2:1,regnames[sp]);
+ push(ISHWORD(t)?2:1);
+ }
+ continue;
+ }
+ if(((regs[acc]&®s[ix])||(t&NQ)==CHAR)&&(p->q1.flags&KONST)&&!isreg(z)){
+ eval_const(&p->q1.val,t);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&((p->z.flags&(REG|DREFOBJ))!=DREFOBJ||(t&NQ)==CHAR)&&(!p->z.am||p->z.am->flags!=ACC_IND||(t&NQ)==CHAR)){
+ emit(f,"\tclr\t");
+ if(c==ASSIGN){
+ emit_obj(f,&p->z,t);emit(f,"\n");
+ }else{
+ emit(f,CPU==6812?"1,-sp\n":",-s\n");
+ push(1);
+ }
+ if(!ISHWORD(t)) continue;
+ emit(f,"\tclr\t");
+ if(c==ASSIGN){
+ mobj=p->z;
+ inc_addr(&mobj,1,t);
+ emit_obj(f,&mobj,t);emit(f,"\n");
+ }else{
+ emit(f,CPU==6812?"1,-sp\n":",-s\n");
+ push(1);
+ }
+ continue;
+ }
+
+ }
+ if(c==PUSH){
+ int st=0;
+ if(isreg(q1)){
+ reg=p->q1.reg;
+ }else{
+ if((t&NQ)==CHAR||!regs[acc]||scratchreg(acc,p)) reg=acc;
+ else if(!regs[ix]||scratchreg(ix,p)) reg=ix;
+ else if(regused[iy]&&(!regs[iy]||scratchreg(iy,p))) reg=iy;
+ else if(regused[iu]&&!drel&&CPU!=6812&&(!regs[iu]||scratchreg(iu,p))) reg=iu;
+ else reg=acc;
+ if(regs[reg]&&!scratchreg(reg,p)){
+ st=1;
+ emit(f,"\tst%s\t%ld,%s\n",regnames[reg],(long)loff-roff-2-stackoffset,regnames[sp]);
+ }
+ load_reg(f,reg,&p->q1,t);
+ }
+ if((t&NQ)==CHAR)
+ emit(f,SPUSH("b"));
+ else if(reg==ix)
+ emit(f,SPUSH("x"));
+ else if(reg==iy)
+ emit(f,SPUSH("y"));
+ else if(reg==iu)
+ emit(f,SPUSH("u"));
+ else
+ emit(f,SPUSHD);
+ push(zm2l(p->q2.val.vmax));
+ if(st)
+ emit(f,"\tld%s\t%ld,%s\n",regnames[reg],(long)loff-roff-2-stackoffset,regnames[sp]);
+ continue;
+ }
+ if(c==ASSIGN){
+ if(isreg(q1)&&isreg(z)){
+ if(p->q1.reg!=p->z.reg)
+ emit(f,"\ttfr\t%s,%s\n",regnames[p->q1.reg],regnames[p->z.reg]);
+ }else if(isreg(q1)){
+ store_reg(f,p->q1.reg,&p->z,t);
+ }else if(isreg(z)){
+ load_reg(f,p->z.reg,&p->q1,t);
+ }else{
+ reg=get_reg(f,p,t);
+ load_reg(f,reg,&p->q1,t);
+ store_reg(f,reg,&p->z,t);
+ }
+ continue;
+ }
+ ierror(0);
+ }
+ if(c==ADDRESS){
+ int px=0;
+ if(isreg(z)){
+ reg=p->z.reg;
+ }else if(!regs[ix]){
+ reg=ix;
+ }else if(!regs[iy]){
+ reg=iy;
+ }else{
+ /*FIXME: test if x used in q1 */
+ px=1;
+ emit(f,SPUSH("x"));
+ reg=ix;
+ push(2);
+ }
+ load_addr(f,reg,&p->q1);
+ if(!(p->z.flags®)||p->z.reg!=reg)
+ store_reg(f,reg,&p->z,p->typf2);
+ if(px){
+ emit(f,SPULL("x"));
+ pop(2);
+ }
+ continue;
+ }
+
+ if((c==MULT||c==DIV||(c==MOD&&(p->typf&UNSIGNED)))&&isconst(q2)){
+ long ln;
+ eval_const(&p->q2.val,t);
+ if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+ if((ln=pof2(vumax))&&ln<5){
+ if(c==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ c=p->code=c=AND;
+ }else{
+ vmax=l2zm(ln-1);
+ if(c==DIV) p->code=c=RSHIFT; else p->code=c=LSHIFT;
+ }
+ c=p->code;
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ if(c==AND){
+ insert_const(&p->q2.val,t);
+ }else{
+ insert_const(&p->q2.val,t);
+ p->typf2=INT;
+ }
+ }
+ }
+ }
+ if(c==MOD||c==DIV){
+ ierror(0);
+ continue;
+ }
+
+
+ if((c==ADD||c==SUB)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&(p->q1.flags&(REG|DREFOBJ))!=REG&&(p->q1.flags&(REG|DREFOBJ))!=DREFOBJ&&!p->q1.am&&!p->z.am&&compare_objects(&p->q1,&p->z)){
+ eval_const(&p->q2.val,t);
+ if(c==SUB) vmax=zmsub(Z0,vmax);
+ if((t&NQ)==CHAR&&zmeqto(vmax,Z1)){
+ emit(f,"\tinc\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ continue;
+ }else if((t&NQ)==CHAR&&zmeqto(vmax,l2zm(-1L))){
+ emit(f,"\tdec\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ continue;
+ }else if(((t&NQ)==SHORT||(t&NQ)==INT)&&zmeqto(vmax,l2zm(1L))){
+ inc_addr(&p->z,1,t);
+ emit(f,"\tinc\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,++label);
+ inc_addr(&p->z,-1,t);
+ emit(f,"\tinc\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ continue;
+ }else if(regs[acc]&&((t&NQ)==SHORT||(t&NQ)==INT)&&zmeqto(vmax,l2zm(-1L))){
+ inc_addr(&p->z,1,t);
+ emit(f,"\ttst\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"\tbne\t%s%d\n",labprefix,++label);
+ inc_addr(&p->z,-1,t);
+ emit(f,"\tdec\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ emit(f,"%s%d:\n",labprefix,label);
+ inc_addr(&p->z,1,t);
+ emit(f,"\tdec\t");
+ emit_obj(f,&p->z,t);
+ emit(f,"\n");
+ continue;
+ }
+ }
+
+ if((c>=LSHIFT&&c<=MOD)||c==ADDI2P||c==SUBIFP||c==SUBPFP||(c>=OR&&c<=AND)||c==COMPARE){
+ char *s;
+ /*FIXME: nicht immer besser*/
+ if(ISLWORD(t)&&c==LSHIFT&&isconst(q2)){
+ eval_const(&p->q2.val,t);
+ if(zm2l(vmax)==1){
+ p->code=c=ADD;
+ p->q2=p->q1;
+ }
+ }
+ if((c==ADD||c==ADDI2P||c==MULT||(c>=OR&&c<=AND))&&isreg(q2)&&!isreg(q1)&&!short_add){
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ }
+ if((c==ADD||c==MULT||(c>=OR&&c<=AND))&&isreg(q2)&&p->q2.reg==acc&&!short_add){
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ }
+ if(c==MULT||c==MOD){
+ if((!isreg(z)||p->z.reg!=acc)&®s[acc]&&!scratchreg(acc,p))
+ get_acc(f,p);
+ reg=acc;
+ /*FIXME: y bzw. x-Register*/
+ }else if(c==LSHIFT||c==RSHIFT||c==AND||c==OR||c==XOR){
+ if((!isreg(z)||p->z.reg!=acc)&®s[acc]&&!scratchreg(acc,p))
+ get_acc(f,p);
+ reg=acc;
+ }else if(c==DIV){
+ reg=ix;
+ ierror(0);
+ }else if(isreg(z)){
+ reg=p->z.reg;
+ }else if(isreg(q1)&&(c==COMPARE||scratchreg(p->q1.reg,p))){
+ reg=p->q1.reg;
+ }else{
+ if(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==COMPARE){
+ if(ISRACC(q2))
+ reg=acc;
+ else
+ reg=get_reg(f,p,t);
+ }else{
+ get_acc(f,p);
+ reg=acc;
+ }
+ }
+ if(c==ADD||c==ADDI2P||c==SUB||c==SUBIFP){
+ int opdone=0;
+ if(isreg(q1)){
+ if(ISIDX(reg)&&ISIDX(p->q1.reg)&&isconst(q2)){
+ eval_const(&p->q2.val,short_add?short_add:q2typ(p));
+ if(CPU==6812&&p->q1.reg==reg&&zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL))){
+ emit(f,"\t%s%s\n",c==SUB?"de":"in",regnames[reg]);
+ /*FIXME: condition-codes for bne/beq could be used */
+ }else{
+ emit(f,"\tlea%s\t%ld,%s\n",regnames[reg],c==SUB?SGN16(-zm2l(vmax)):SGN16(zm2l(vmax)),regnames[p->q1.reg]);
+ }
+ opdone=1;
+ }else if((c==ADD||c==ADDI2P)&&ISIDX(reg)&&ISIDX(p->q1.reg)&&ISRACC(q2)){
+ emit(f,"\tlea%s\t%s,%s\n",regnames[reg],((t&NQ)==CHAR||(short_add&NQ)==CHAR)?"b":"d",regnames[p->q1.reg]);
+ opdone=1;
+ }else if((c==ADD||c==ADDI2P)&&ISIDX(reg)&&ISACC(p->q1.reg)&&ISRIDX(q2)){
+ emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[p->q2.reg]);
+ opdone=1;
+ }else if((c==ADD||c==ADDI2P)&&p->q1.reg==acc&&ISIDX(reg)&&!short_add){
+ load_reg(f,reg,&p->q2,t);
+ emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[reg]);
+ opdone=1;
+ }else if((c==ADD||c==ADDI2P)&&p->q1.reg==acc&&ISIDX(reg)&&(short_add&NU)==(UNSIGNED|CHAR)&&scratchreg(acc,p)){
+ emit(f,"\taddb\t");
+ emit_obj(f,&p->q2,short_add);
+ emit(f,"\n");
+ emit(f,"\tadca\t#0\n");
+ emit(f,"\ttfr\td,y\n");
+ opdone=1;
+ }else if((c==ADD||c==ADDI2P)&&ISACC(p->q1.reg)&&ISRACC(z)&&isreg(q2)&&ISIDX(p->q2.reg)){
+ if(!scratchreg(p->q2.reg,p)) emit(f,"\texg\t%s,%s\n",regnames[acc],regnames[p->q2.reg]);
+ emit(f,"\tlea%s\t%s,%s\n",regnames[p->q2.reg],regnames[acc],regnames[p->q2.reg]);
+ emit(f,"\texg\t%s,%s\n",regnames[acc],regnames[p->q2.reg]);
+ opdone=1;
+ }else if(p->q1.reg!=reg){
+ if(c==ADD||c==ADDI2P||!ISRACC(q2))
+ emit(f,"\ttfr\t%s,%s\n",regnames[p->q1.reg],regnames[reg]);
+ }
+ }else if(short_add&&c==SUB&®==acc&&!(short_add&UNSIGNED)){
+ load_reg(f,reg,&p->q2,short_add);
+ emit(f,"\tclra\n");
+ emit(f,"\tnegb\n");
+ emit(f,"\tsbca\t#0\n");
+ emit(f,"\taddd\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ store_reg(f,reg,&p->z,ztyp(p));
+ continue;
+ }else if(short_add&&c==ADD&®==acc){
+ load_reg(f,reg,&p->q2,short_add);
+ if(short_add&UNSIGNED)
+ emit(f,"\tclra\n");
+ else
+ emit(f,SEX);
+ emit(f,"\taddd\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ store_reg(f,reg,&p->z,ztyp(p));
+ continue;
+ }else{
+ if(!ISRACC(q2))
+ load_reg(f,reg,&p->q1,q1typ(p));
+ }
+ if(!opdone){
+ if(reg==acc){
+ if(ISRACC(q2)){
+ if(!ISRACC(z)) get_acc(f,p);
+ if(c==ADD||c==ADDI2P){
+ if(short_add){
+ if(short_add&UNSIGNED)
+ emit(f,"\tclra\n");
+ else
+ emit(f,SEX);
+ emit(f,"\taddd\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }else{
+ if(CPU==6812)
+ emit(f,"\tasld\n"); /* only cases with q1=q2=acc should remain */
+ else{
+ emit(f,"\taslb\n");
+ if((t&NQ)!=CHAR)
+ emit(f,"\trola\n");
+ }
+ }
+ }else{
+ if(short_add){
+ if(short_add&UNSIGNED)
+ emit(f,"\tld%sa\t#255\n",(CPU==6812)?"a":"");
+ else{
+ emit(f,SEX);
+ emit(f,"\tnega\n");
+ }
+ emit(f,"\tnegb\n\tsbca\t#0\n");
+ }else if((t&NQ)!=CHAR){
+ emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+ }else{
+ emit(f,"\tnegb\n");
+ }
+
+ if(ISRIDX(q1)){
+ emit(f,"\t%s%s\n",CPU==6812?"psh":"pshs\t",regnames[p->q1.reg]);
+ emit(f,"\taddd\t%s\n",CPU==6812?"1,s+":",s++");
+ }else{
+ emit(f,"\taddd\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ }
+ }else{
+ if(ISRIDX(q2)){
+ if(CPU==6812)
+ emit(f,"\tpsh%s\n",regnames[p->q2.reg]);
+ else
+ emit(f,"\tpshs\t%s\n",regnames[p->q2.reg]);
+ push(2);pop(2);
+ if(CPU==6812)
+ emit(f,"\t%sd\t2,%s+\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]);
+ else
+ emit(f,"\t%sd\t,%s++\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]);
+ }else{
+ emit(f,"\t%s%s\t",(c==ADD||c==ADDI2P)?"add":"sub",(short_add||(t&NQ)==CHAR)?"b":"d");
+ emit_obj(f,&p->q2,short_add?short_add:t);emit(f,"\n");
+ if(short_add){
+ if(short_add&UNSIGNED)
+ emit(f,"\t%s\t#0\n",c==ADD?"adca":"sbca");
+ else
+ ierror(0);
+ }
+ if(drel&&(p->q2.flags&VARADR)){
+ if(CPU==6812) ierror(0);
+ emit(f,"\tpshs\t%s\n",regnames[iu]);push(2);
+ emit(f,"\t%sd\t,%s++\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]);
+ pop(2);
+ }
+ }
+ }
+ cc=&p->z;cc_t=t;
+ }else{
+ if(isconst(q2)){
+ long l;
+ eval_const(&p->q2.val,short_add?short_add:t);
+ l=zm2l(vmax);
+ if(c==SUB) l=-l;
+ /*FIXME: condition-codes for bne/beq could be used */
+ if(l==1&®==ix&&CPU==6812){
+ emit(f,"\tinx\n");
+ }else if(l==1&®==iy&&CPU==6812){
+ emit(f,"\tiny\n");
+ }else if(l==-1&®==ix&&CPU==6812){
+ emit(f,"\tdex\n");
+ }else if(l==-1&®==iy&&CPU==6812){
+ emit(f,"\tdey\n");
+ }else{
+ emit(f,"\tlea%s\t%ld,%s\n",regnames[reg],SGN16(l),regnames[reg]);
+ }
+ }else{
+ if(c!=ADD&&c!=ADDI2P){
+ if(!ISRACC(q2)){
+ if(!scratchreg(acc,p))
+ get_acc(f,p);
+ load_reg(f,acc,&p->q2,t);
+ if((t&NQ)!=CHAR){
+ emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+ }else{
+ emit(f,"\tnegb\n");
+ }
+ /*load_reg(f,reg,&p->q1,t);*/
+ }else{
+ get_acc(f,p);
+ load_reg(f,reg,&p->q1,t);
+ if((t&NQ)==CHAR)
+ emit(f,"\tnegb\n");
+ else
+ emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
+ }
+ }else if(!ISRACC(q2)){
+ get_acc(f,p);
+ if(short_add){
+ load_reg(f,acc,&p->q2,short_add);
+ if(short_add&UNSIGNED){
+ if(reg==ix){
+ emit(f,"\tabx\n");
+ store_reg(f,reg,&p->z,ztyp(p));
+ continue;
+ }else{
+ emit(f,"\tclra\n");
+ }
+ }else
+ t=CHAR;
+ }else
+ load_reg(f,acc,&p->q2,t);
+ }else{
+ load_reg(f,reg,&p->q1,t);
+ if(short_add&UNSIGNED)
+ emit(f,"\tclra\n");
+ emit(f,"\tlea%s\t%s,%s\n",regnames[reg],((t&NU)==CHAR||(short_add&NU)==CHAR)?"b":"d",regnames[reg]);
+ store_reg(f,reg,&p->z,ztyp(p));
+ continue;
+ }
+ emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[reg]);
+ }
+ }
+ }
+ store_reg(f,reg,&p->z,ztyp(p));
+ continue;
+ }
+ if(c!=LSHIFT&&c!=RSHIFT)
+ load_reg(f,reg,&p->q1,t);
+ if(c==MULT){
+ if(CPU==6812){
+ int py=0;
+ if(reg!=acc) ierror(reg);
+ if(!ISRY(q2)&®s[iy]){
+ emit(f,"\tpshy\n");
+ push(2);
+ py=1;
+ }
+ load_reg(f,iy,&p->q2,t);
+ emit(f,"\temul\n");
+ if(py){
+ emit(f,SPULL("y"));
+ pop(2);
+ }
+ store_reg(f,acc,&p->z,t);
+ continue;
+ }else
+ ierror(0);
+ }
+ if(c==LSHIFT||c==RSHIFT){
+ if(isconst(q2)){
+ int l,oldl;
+ load_reg(f,acc,&p->q1,t);
+ eval_const(&p->q2.val,t);
+ oldl=l=zm2l(vmax);
+ if(l>=24){
+ if(CPU!=6812&&!optsize)
+ emit(f,"\tldd\t#0\n");
+ else
+ emit(f,"\tclra\n\tclrb\n");
+ l=0;
+ }
+ if(l>=8){
+ if(c==LSHIFT)
+ emit(f,"\t%s\n\tclrb\n",(CPU==6812)?"tba":"tfr\tb,a");
+ else{
+ if(t&UNSIGNED)
+ emit(f,"\ttfr\ta,b\n\tclra\n");
+ else{
+ emit(f,"\ttfr\ta,b\n");
+ emit(f,SEX);
+ }
+ }
+ l-=8;
+ }
+ while(l--){
+ if(c==RSHIFT){
+ if(t&UNSIGNED){
+ if((t&NQ)==CHAR)
+ emit(f,"\tlsrb\n");
+ else
+ emit(f,CPU==6809?"\tlsra\n\trorb\n":"\tlsrd\n");
+ }else{
+ if(oldl>12||(t&NQ)==CHAR)
+ emit(f,"\tasrb\n");
+ else
+ emit(f,"\tasra\n\trorb\n");
+ }
+ }else{
+ if((t&NQ)==CHAR)
+ emit(f,"\taslb\n");
+ else
+ emit(f,CPU==6809?"\taslb\n\trola\n":"\tasld\n");
+ }
+ }
+ }else{
+ int px;char *s;
+ if(regs[ix]&&!scratchreg(ix,p)&&(!isreg(z)||p->z.reg!=ix)){
+ emit(f,SPUSH("x"));
+ push(2);px=1;
+ }else
+ px=0;
+ if((p->typf2&NQ)==CHAR){
+ load_reg(f,acc,&p->q2,p->typf2);
+ emit(f,(p->typf2&UNSIGNED)?"\tclra\n":SEX);
+ emit(f,"\ttfr\td,x\n");
+ }else
+ load_reg(f,ix,&p->q2,t);
+ load_reg(f,acc,&p->q1,p->typf);
+ if((t&NQ)==CHAR)
+ emit(f,(p->typf2&UNSIGNED)?"\tclra\n":SEX);
+ if(c==LSHIFT) s="lsl";
+ else if(t&UNSIGNED) s="lsr";
+ else s="asr";
+ emit(f,"\t.global\t%s__%s\n",idprefix,s);
+ emit(f,"\t%s\t%s__%s\n",jsrinst,idprefix,s);
+ if(px){
+ emit(f,SPULL("x"));
+ /*emit(f,"\tpul%s\n",regnames[ix]);*/
+ pop(2);
+ }
+ }
+ cc=0;
+ store_reg(f,acc,&p->z,t);
+ continue;
+ }
+ if(c>=OR&&c<=AND){
+ s=logicals[c-OR];
+ if(p->q2.am&&p->q2.am->flags==ACC_IND){
+ mobj=p->q1;p->q1=p->q2;p->q2=mobj;
+ }
+ if(p->q2.flags&KONST){
+ unsigned long l,h;
+ eval_const(&p->q2.val,t);
+ l=zum2ul(vumax);
+ if((t&NQ)!=CHAR){
+ h=(l>>bitsperbyte)&bytemask;
+ if(c==AND&&h==0)
+ emit(f,"\tclra\n");
+ else if(c==XOR&&h==bytemask)
+ emit(f,"\tcoma\n");
+ else if((c==AND&&h!=bytemask)||(c==OR&&h!=0)||(c==XOR&&h!=0))
+ emit(f,"\t%sa\t#%lu\n",s,h);
+ }
+ h=l&bytemask;
+ if(c==AND&&h==0)
+ emit(f,"\tclrb\n");
+ else if(c==XOR&&h==bytemask)
+ emit(f,"\tcomb\n");
+ else if((c==AND&&h!=bytemask)||(c==OR&&h!=0)||(c==XOR&&h!=0))
+ emit(f,"\t%sb\t#%lu\n",s,h);
+ }else{
+ if(isreg(q2)){
+ if(p->q2.reg==acc){
+ if(c==XOR){
+ emit(f,"\tclrb\n");
+ if((t&NQ)!=CHAR) emit(f,"\tclra\n");
+ }
+ }else{
+ if((t&NQ)==CHAR){
+ emit(f,SPUSH("a"));
+ push(1);
+ emit(f,"\t%sa\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]);
+ pop(1);
+ }else{
+ emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[p->q2.reg]);
+ push(2);
+ emit(f,"\t%sa\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]);
+ emit(f,"\t%sb\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]);
+ pop(2);
+ }
+ }
+ }else if((p->q2.flags&(REG|DREFOBJ))==DREFOBJ&&(t&NQ)!=CHAR){
+ int xr=0;
+ if(!regs[ix]) xr=ix;
+ else if(!regs[iy]) xr=iy;
+ else{
+ xr=ix;
+ emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[xr]);
+ push(2);
+
+ }
+ BSET(regs_modified,xr);
+ load_addr(f,xr,&p->q2);
+ if((t&NQ)==CHAR)
+ emit(f,"\t%sb\t0,%s\n",s,regnames[xr]);
+ else{
+ emit(f,"\t%sa\t0,%s\n",s,regnames[xr]);
+ emit(f,"\t%sb\t1,%s\n",s,regnames[xr]);
+ }
+ if(regs[ix]&&xr==ix){
+ emit(f,SPULL("x"));
+ pop(2);
+ }
+ }else{
+ emit(f,"\t%sb\t",s);
+ if((t&NQ)!=CHAR) inc_addr(&p->q2,1,t);
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ if((t&NQ)!=CHAR){
+ inc_addr(&p->q2,-1,t);
+ emit(f,"\t%sa\t",s);
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ }
+ }
+ }
+ cc=0;
+ store_reg(f,reg,&p->z,t);
+ continue;
+ }else if(c==COMPARE){
+ lastcomp=t;
+ if(isreg(q2)){
+ emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[p->q2.reg]);
+ push(2);
+ }
+ if(reg==acc){
+ if((t&NQ)==CHAR)
+ emit(f,"\tcmpb\t");
+ else
+ emit(f,SCMP("d"));
+ }else if(reg==ix){
+ emit(f,SCMP("x"));
+ }else if(reg==iy){
+ emit(f,SCMP("y"));
+ }else if(reg==iu){
+ emit(f,SCMP("u"));
+ }else
+ ierror(0);
+ if(isreg(q2)){
+ if(CPU==6812)
+ emit(f,"2,%s+\n",regnames[sp]);
+ else
+ emit(f,",%s++\n",regnames[sp]);
+ pop(2);
+ }else{
+ emit_obj(f,&p->q2,t);emit(f,"\n");
+ }
+ continue;
+ }
+ ierror(0);
+ }
+ pric2(stdout,p);
+ ierror(0);
+ }
+ if(notpopped){
+ gen_pop(f,notpopped);
+ notpopped=0;
+ }
+ function_bottom(f,v,loff);
+ if(debug_info){
+ emit(f,"%s%d:\n",labprefix,++label);
+ dwarf2_function(f,v,label);
+ if(f) section=-1;
+ }
+}
+
+int shortcut(int c,int t)
+{
+ if(c==COMPARE||c==ADD||c==SUB||c==AND||c==OR||c==XOR) return 1;
+ if((c==LSHIFT||c==RSHIFT)&&ISCHWORD(t&NQ)) return 1;
+ return 0;
+}
+
+void cleanup_cg(FILE *f)
+{
+ struct fpconstlist *p;
+ unsigned char *ip;
+ if(f&&stack_check)
+ emit(f,"\t.global\t%s__stack_check\n",idprefix);
+ while(p=firstfpc){
+ if(f){
+ if(section!=RODATA){
+ emit(f,rodataname);if(f) section=RODATA;
+ }
+ emit(f,"%s%d\n\t%s\t",labprefix,p->label,dct[LONG]);
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ if((p->typ&NQ)==DOUBLE||(p->typ&NQ)==LDOUBLE){
+ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ emit(f,"\n");
+ }
+ firstfpc=p->next;
+ free(p);
+ }
+}
+
+int reg_parm(struct reg_handle *p,struct Typ *t,int mode,struct Typ *fkt)
+{
+ if(p->gpr) return 0;
+ if(ISSCALAR(t->flags)&&!ISFLOAT(t->flags)&&!ISLWORD(t->flags)){
+ p->gpr=1;
+ return acc;
+ }
+ return 0;
+}
+
+void insert_const(union atyps *p,int t)
+/* Traegt Konstante in entprechendes Feld ein. */
+{
+ if(!p) ierror(0);
+ t&=NU;
+ if(t==BIT) {if(zmeqto(zc2zm(vchar),l2zm(0L))) p->vchar=zm2zc(l2zm(0L)); else p->vchar=zm2zc(l2zm(1L));return;}
+ if(t==CHAR) {p->vchar=vchar;return;}
+ if(t==SHORT) {p->vshort=vshort;return;}
+ if(t==INT) {p->vint=vint;return;}
+ if(t==LONG) {p->vlong=vlong;return;}
+ if(t==LLONG) {p->vllong=vllong;return;}
+ if(t==MAXINT) {p->vmax=vmax;return;}
+ if(t==(UNSIGNED|BIT)) {if(zumeqto(zuc2zum(vuchar),ul2zum(0UL))) p->vuchar=zum2zuc(ul2zum(0UL)); else p->vuchar=zum2zuc(ul2zum(1UL));return;}
+ if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
+ if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
+ if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
+ if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
+ if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
+ if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
+ if(t==FLOAT) {p->vfloat=vfloat;return;}
+ if(t==DOUBLE) {p->vdouble=vdouble;return;}
+ if(t==LDOUBLE) {p->vldouble=vldouble;return;}
+ if(t==NPOINTER) {p->vuint=vuint;return;}
+ if(t==FPOINTER||t==HPOINTER) {p->vulong=vulong;return;}
+}
+void eval_const(union atyps *p,int t)
+/* Weist bestimmten globalen Variablen Wert einer CEXPR zu. */
+{
+ int f=t&NQ;
+ if(!p) ierror(0);
+ if(f==MAXINT||(f>=BIT&&f<=LLONG)){
+ if(!(t&UNSIGNED)){
+ if(f==BIT){
+ if(zmeqto(zc2zm(p->vchar),l2zm(0L))) vmax=l2zm(0L); else vmax=l2zm(1L);
+ }else if(f==CHAR) vmax=zc2zm(p->vchar);
+ else if(f==SHORT)vmax=zs2zm(p->vshort);
+ else if(f==INT) vmax=zi2zm(p->vint);
+ else if(f==LONG) vmax=zl2zm(p->vlong);
+ else if(f==LLONG) vmax=zll2zm(p->vllong);
+ else if(f==MAXINT) vmax=p->vmax;
+ else ierror(0);
+ vumax=zm2zum(vmax);
+ vldouble=zm2zld(vmax);
+ }else{
+ if(f==BIT){
+ if(zumeqto(zuc2zum(p->vuchar),ul2zum(0UL))) vumax=ul2zum(0UL); else vumax=ul2zum(1UL);
+ }else if(f==CHAR) vumax=zuc2zum(p->vuchar);
+ else if(f==SHORT)vumax=zus2zum(p->vushort);
+ else if(f==INT) vumax=zui2zum(p->vuint);
+ else if(f==LONG) vumax=zul2zum(p->vulong);
+ else if(f==LLONG) vumax=zull2zum(p->vullong);
+ else if(f==MAXINT) vumax=p->vumax;
+ else ierror(0);
+ vmax=zum2zm(vumax);
+ vldouble=zum2zld(vumax);
+ }
+ }else{
+ if(ISPOINTER(f)){
+ if(f==NPOINTER)
+ vumax=zui2zum(p->vuint);
+ else
+ vumax=zul2zum(p->vulong);
+ vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
+ }else{
+ if(f==FLOAT) vldouble=zf2zld(p->vfloat);
+ else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
+ else vldouble=p->vldouble;
+ vmax=zld2zm(vldouble);
+ vumax=zld2zum(vldouble);
+ }
+ }
+ vfloat=zld2zf(vldouble);
+ vdouble=zld2zd(vldouble);
+ vuchar=zum2zuc(vumax);
+ vushort=zum2zus(vumax);
+ vuint=zum2zui(vumax);
+ vulong=zum2zul(vumax);
+ vullong=zum2zull(vumax);
+ vchar=zm2zc(vmax);
+ vshort=zm2zs(vmax);
+ vint=zm2zi(vmax);
+ vlong=zm2zl(vmax);
+ vllong=zm2zll(vmax);
+}
+void printval(FILE *f,union atyps *p,int t)
+/* Gibt atyps aus. */
+{
+ t&=NU;
+ if(t==BIT){vmax=zc2zm(p->vchar);fprintf(f,"B%d",!zmeqto(vmax,l2zm(0L)));}
+ if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);fprintf(f,"UB%d",!zumeqto(vmax,ul2zum(0UL)));}
+ if(t==CHAR){vmax=zc2zm(p->vchar);printzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
+ if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
+ if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
+ if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
+ if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
+ if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
+ if(t==(UNSIGNED|INT)||t==NPOINTER){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
+ if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
+ if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
+ if(t==MAXINT) printzm(f,p->vmax);
+ if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax);
+}
+void emitval(FILE *f,union atyps *p,int t)
+{
+ t&=NU;
+ if((t&NQ)==NPOINTER) t=(UNSIGNED|INT);
+ if(t==BIT){vmax=zc2zm(p->vchar);emit(f,"%d",!zmeqto(vmax,l2zm(0L)));}
+ if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);emit(f,"%d",!zumeqto(vmax,ul2zum(0UL)));}
+ if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
+ if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
+ if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
+ if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
+ if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
+ if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
+ if(t==LDOUBLE){emitzld(f,p->vldouble);}
+ if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
+ if(t==(UNSIGNED|INT)||t==NPOINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
+ if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
+ if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
+ if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
+ if(t==MAXINT) emitzm(f,p->vmax);
+ if(t==(UNSIGNED|MAXINT)) emitzum(f,p->vumax);
+}
+
+void conv_typ(struct Typ *p)
+/* Erzeugt extended types in einem Typ. */
+{
+ char *attr;
+ while(p){
+ if(ISPOINTER(p->flags)){
+ p->flags=((p->flags&~NU)|POINTER_TYPE(p->next));
+ if(attr=p->next->attr){
+ if(strstr(attr,STR_NEAR))
+ p->flags=((p->flags&~NU)|NPOINTER);
+ if(strstr(attr,STR_FAR))
+ p->flags=((p->flags&~NU)|FPOINTER);
+ if(strstr(attr,STR_HUGE))
+ p->flags=((p->flags&~NU)|HPOINTER);
+ }
+ }
+ if(ISINT(p->flags)&&(attr=p->attr)&&strstr(attr,"bit"))
+ p->flags=((p->flags&~NU)|BIT);
+ p=p->next;
+ }
+}
+
+void init_db(FILE *f)
+{
+ dwarf2_setup(sizetab[HPOINTER],".byte",".2byte",".4byte",".4byte",labprefix,idprefix,".section");
+ dwarf2_print_comp_unit_header(f);
+}
+void cleanup_db(FILE *f)
+{
+ dwarf2_cleanup(f);
+ if(f) section=-1;
+}
diff --git a/machines/rf12/machine.dt b/machines/rf12/machine.dt
new file mode 100755
index 0000000..7d54552
--- /dev/null
+++ b/machines/rf12/machine.dt
@@ -0,0 +1,14 @@
+S12BS
+S12BU
+S24BS
+S24BU
+S24BS
+S24BU
+S48BS
+S48BU
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S48BU
diff --git a/machines/rf12/machine.h b/machines/rf12/machine.h
new file mode 100755
index 0000000..a90ae8f
--- /dev/null
+++ b/machines/rf12/machine.h
@@ -0,0 +1,188 @@
+/* Example of a code-generator for Motorola 68hc12 16bit microcontrollers.*/
+
+#include "dt.h"
+
+/* We have extended types! What we have to do to support them: */
+/* - #define HAVE_EXT_TYPES
+ - #undef all standard types
+ - #define all standard types plus new types
+ - write eval_const and insert_const
+ - write typedefs for zmax and zumax
+ - write typname[]
+ - write conv_typ()
+ - optionally #define ISPOINTER, ISARITH, ISINT etc.
+ - optionally #define HAVE_TGT_PRINTVAL and write printval
+ - optionally #define POINTER_TYPE
+ - optionally #define HAVE_TGT_FALIGN and write falign
+ - optionally #define HAVE_TGT_SZOF and write szof
+ - optionally add functions for attribute-handling
+*/
+#define HAVE_EXT_TYPES 1
+
+#define HAVE_TGT_PRINTVAL
+
+#undef CHAR
+#undef SHORT
+#undef INT
+#undef LONG
+#undef LLONG
+#undef FLOAT
+#undef DOUBLE
+#undef LDOUBLE
+#undef VOID
+#undef POINTER
+#undef ARRAY
+#undef STRUCT
+#undef UNION
+#undef ENUM
+#undef FUNKT
+#undef MAXINT
+#undef MAX_TYPE
+
+#define BIT 1
+#define CHAR 2
+#define SHORT 3
+#define INT 4
+#define LONG 5
+#define LLONG 6
+#define FLOAT 7
+#define DOUBLE 8
+#define LDOUBLE 9
+#define VOID 10
+#define NPOINTER 11
+#define FPOINTER 12
+#define HPOINTER 13
+#define ARRAY 14
+#define STRUCT 15
+#define UNION 16
+#define ENUM 17
+#define FUNKT 18
+
+#define MAXINT 19
+
+#define MAX_TYPE MAXINT
+
+#define POINTER_TYPE(x) pointer_type(x)
+extern int pointer_type();
+#define ISPOINTER(x) ((x&NQ)>=NPOINTER&&(x&NQ)<=HPOINTER)
+#define ISSCALAR(x) ((x&NQ)>=BIT&&(x&NQ)<=HPOINTER)
+#define ISINT(x) ((x&NQ)>=BIT&&(x&NQ)<=LLONG)
+#define PTRDIFF_T(x) ((x)==HPOINTER?LONG:INT)
+
+typedef zllong zmax;
+typedef zullong zumax;
+
+union atyps{
+ zchar vchar;
+ zuchar vuchar;
+ zshort vshort;
+ zushort vushort;
+ zint vint;
+ zuint vuint;
+ zlong vlong;
+ zulong vulong;
+ zllong vllong;
+ zullong vullong;
+ zmax vmax;
+ zumax vumax;
+ zfloat vfloat;
+ zdouble vdouble;
+ zldouble vldouble;
+};
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Not used in this code-generrator. */
+struct AddressingMode{
+ int flags;
+ int base;
+ long offset;
+ struct Var *v;
+};
+
+/* This type will be added to every IC. Can be used by the cg. */
+#define HAVE_EXT_IC 1
+struct ext_ic {
+ int flags;
+ int r;
+ long offset;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR 6
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 20
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+extern int MINADDI2P;
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 1
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 0
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+extern int switchsubs;
+#define SWITCHSUBS switchsubs
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+#define HAVE_REGPARMS 1
+
+struct reg_handle {
+ int gpr;
+};
+
+/* We use unsigned int as size_t rather than unsigned long which */
+/* is the default setting. */
+#define HAVE_INT_SIZET 1
+
+/* We have register pairs. */
+#define HAVE_REGPAIRS 1
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+#define HAVE_TARGET_RALLOC 1
+#define cost_load_reg(r,v) 4
+#define cost_save_reg(r,v) 4
+#define cost_move_reg(i,j) 2
+#define cost_pushpop_reg(r) 2
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/* We have asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 1
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES 1
+
+/* We use builtin libcalls for some operations */
+#define HAVE_LIBCALLS 1
+
+/* We prefer BNE rather than BGT. */
+#define HAVE_WANTBNE 1
+
+#define HAVE_POF2OPT 1
diff --git a/machines/src/machine.c b/machines/src/machine.c
new file mode 100755
index 0000000..f4f25af
--- /dev/null
+++ b/machines/src/machine.c
@@ -0,0 +1,1092 @@
+/* C src backend for vbcc
+ */
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc C source code-generator V0.1a (c) in 2011 by Volker Barthelmann";
+
+
+int g_flags[MAXGF]={0};
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+ they collide with the frontend */
+char *g_flags_name[MAXGF]={0};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. will be initialized in init_cg(),
+ register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+ estimated cost-saving can be obtained by several registers, the
+ one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__interrupt",0};
+
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]= {1,1,2,4,4,4,4,8,8,1,4,1,1,1,4,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp={LONG},ldbl={DOUBLE},lchar={CHAR};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+ "__GENERIC__",
+ 0};
+
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","c","s","i","l","ll","f","d","ld","v","p"};
+static char *udt[MAX_TYPE+1]={"??","uc","us","ui","ul","ull","f","d","ld","v","p"};
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\t.text\n",
+ *dataname="\t.data\n",
+ *bssname="",
+ *rodataname="\t.section\t.rodata\n";
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+#if FIXED_SP
+/* variables to calculate the size and partitioning of the stack-frame
+ in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+#else
+/* variables to keep track of the current stack-offset in the case of
+ a moving stack-pointer */
+static long notpopped,dontpop,stackoffset,maxpushed;
+#endif
+
+static long localsize,rsavesize,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+ stack-pointer; we use a layout like this:
+ ------------------------------------------------
+ | arguments to this function |
+ ------------------------------------------------
+ | return-address [size=4] |
+ ------------------------------------------------
+ | caller-save registers [size=rsavesize] |
+ ------------------------------------------------
+ | local variables [size=localsize] |
+ ------------------------------------------------
+ | arguments to called functions [size=argsize] |
+ ------------------------------------------------
+ All sizes will be aligned as necessary.
+ In the case of FIXED_SP, the stack-pointer will be adjusted at
+ function-entry to leave enough space for the arguments and have it
+ aligned to 16 bytes. Therefore, when calling a function, the
+ stack-pointer is always aligned to 16 bytes.
+ For a moving stack-pointer, the stack-pointer will usually point
+ to the bottom of the area for local variables, but will move while
+ arguments are put on the stack.
+
+ This is just an example layout. Other layouts are also possible.
+*/
+
+static long real_offset(struct obj *o)
+{
+ long off=zm2l(o->v->offset);
+ if(off<0){
+ /* function parameter */
+ off=localsize+rsavesize+4-off-zm2l(maxalign);
+ }
+
+#if FIXED_SP
+ off+=argsize;
+#else
+ off+=stackoffset;
+#endif
+ off+=zm2l(o->val.vmax);
+ return off;
+}
+
+/* Initializes an addressing-mode structure and returns a pointer to
+ that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ am.offset=offset;
+ return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+ char *sec;
+ if(!v->vattr) return 0;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return 0;
+ sec+=strlen("section(");
+ emit(f,"\t.section\t");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/* Generates code to load the address of a variable into register r. */
+{
+ if(!(o->flags&VAR)) ierror(0);
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+ long off=real_offset(o);
+ if(THREE_ADDR){
+ emit(f,"\tadd.%s\t%s,%s,%ld\n",dt(POINTER),regnames[r],regnames[sp],off);
+ }else{
+ emit(f,"\tmov.%s\t%s,%s\n",dt(POINTER),regnames[r],regnames[sp]);
+ if(off)
+ emit(f,"\tadd.%s\t%s,%ld\n",dt(POINTER),regnames[r],off);
+ }
+ }else{
+ emit(f,"\tmov.%s\t%s,",dt(POINTER),regnames[r]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }
+}
+/* Generates code to load a memory object into register r. tmp is a
+ general purpose register which may be used. tmp can be r. */
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+ type&=NU;
+ if(o->flags&VARADR){
+ load_address(f,r,o,POINTER);
+ }else{
+ if((o->flags&(REG|DREFOBJ))==REG&&o->reg==r)
+ return;
+ emit(f,"\tmov.%s\t%s,",dt(type),regnames[r]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }
+}
+
+/* Generates code to store register r into memory object o. */
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+ type&=NQ;
+ emit(f,"\tmov.%s\t",dt(type));
+ emit_obj(f,o,type);
+ emit(f,",%s\n",regnames[r]);
+}
+
+/* Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+
+static struct IC *preload(FILE *,struct IC *);
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *logicals[]={"or","xor","and"};
+static char *arithmetics[]={"slw","srw","add","sub","mullw","divw","mod"};
+
+/* Does some pre-processing like fetching operands from memory to
+ registers etc. */
+static struct IC *preload(FILE *f,struct IC *p)
+{
+ int r;
+
+ if(isreg(q1))
+ q1reg=p->q1.reg;
+ else
+ q1reg=0;
+
+ if(isreg(q2))
+ q2reg=p->q2.reg;
+ else
+ q2reg=0;
+
+ if(isreg(z)){
+ zreg=p->z.reg;
+ }else{
+ if(ISFLOAT(ztyp(p)))
+ zreg=f1;
+ else
+ zreg=t1;
+ }
+
+ if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am){
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,t1,&p->q1,q1typ(p));
+ p->q1.reg=t1;
+ p->q1.flags|=(REG|DREFOBJ);
+ }
+ if(p->q1.flags&&LOAD_STORE&&!isreg(q1)){
+ if(ISFLOAT(q1typ(p)))
+ q1reg=f1;
+ else
+ q1reg=t1;
+ load_reg(f,q1reg,&p->q1,q1typ(p));
+ p->q1.reg=q1reg;
+ p->q1.flags=REG;
+ }
+
+ if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am){
+ p->q2.flags&=~DREFOBJ;
+ load_reg(f,t1,&p->q2,q2typ(p));
+ p->q2.reg=t1;
+ p->q2.flags|=(REG|DREFOBJ);
+ }
+ if(p->q2.flags&&LOAD_STORE&&!isreg(q2)){
+ if(ISFLOAT(q2typ(p)))
+ q2reg=f2;
+ else
+ q2reg=t2;
+ load_reg(f,q2reg,&p->q2,q2typ(p));
+ p->q2.reg=q2reg;
+ p->q2.flags=REG;
+ }
+ return p;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+ if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
+ p->z.flags&=~DREFOBJ;
+ load_reg(f,t2,&p->z,POINTER);
+ p->z.reg=t2;
+ p->z.flags|=(REG|DREFOBJ);
+ }
+ if(isreg(z)){
+ if(p->z.reg!=zreg)
+ emit(f,"\tmov.%s\t%s,%s\n",dt(ztyp(p)),regnames[p->z.reg],regnames[zreg]);
+ }else{
+ store_reg(f,zreg,&p->z,ztyp(p));
+ }
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+ if(p->am){
+ if(p->am->flags&GPR_IND) emit(f,"(%s,%s)",regnames[p->am->offset],regnames[p->am->base]);
+ if(p->am->flags&IMM_IND) emit(f,"(%ld,%s)",p->am->offset,regnames[p->am->base]);
+ return;
+ }
+ if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if(p->flags&DREFOBJ) emit(f,"(");
+ if(p->flags®){
+ emit(f,"%s",regnames[p->reg]);
+ }else if(p->flags&VAR) {
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+ emit(f,"%ld(%s)",real_offset(p),regnames[sp]);
+ else{
+ if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ }
+ }
+ if(p->flags&KONST){
+ emitval(f,&p->val,t&NU);
+ }
+ if(p->flags&DREFOBJ) emit(f,")");
+}
+
+/* Test if there is a sequence of FREEREGs containing FREEREG reg.
+ Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+ while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+ if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+ p=p->next;
+ }
+ return 0;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+ int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+ for(;p;p=p->next){
+ c=p->code;
+ if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+ if(c==LABEL) exit_label=p->typf;
+
+ /* Try const(reg) */
+ if(IMM_IND&&(c==ADDI2P||c==SUBIFP)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+ int base;zmax of;struct obj *o;
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ if(1/*zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))*/){
+ r=p->z.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ am->base=base;
+ am->offset=zm2l(of);
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+ /* Try reg,reg */
+ if(GPR_IND&&c==ADDI2P&&isreg(q2)&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+ int base,idx;struct obj *o;
+ r=p->z.reg;idx=p->q2.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||(q1typ(p2)&NQ)==LLONG) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||(q2typ(p2)&NQ)==LLONG) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||(ztyp(p2)&NQ)==LLONG) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=GPR_IND;
+ am->base=base;
+ am->offset=idx;
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+ rsavesize=0;
+ if(!special_section(f,v)&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+}
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+ emit(f,ret);
+}
+
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+int init_cg(void)
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(8L);
+ char_bit=l2zm(8L);
+
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+
+ regnames[0]="noreg";
+ for(i=FIRST_GPR;i<=LAST_GPR;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"gpr%d",i-FIRST_GPR);
+ regsize[i]=l2zm(4L);
+ regtype[i]=<yp;
+ }
+ for(i=FIRST_FPR;i<=LAST_FPR;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"fpr%d",i-FIRST_FPR);
+ regsize[i]=l2zm(8L);
+ regtype[i]=&ldbl;
+ }
+ for(i=FIRST_CCR;i<=LAST_CCR;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"ccr%d",i-FIRST_CCR);
+ regsize[i]=l2zm(1L);
+ regtype[i]=&lchar;
+ }
+
+ /* Use multiple ccs. */
+ multiple_ccs=0;
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LONG]=t_min(INT);
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=ul2zum(2147483647UL);
+ t_max[LONG]=t_max(INT);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=ul2zum(4294967295UL);
+ tu_max[LONG]=t_max(UNSIGNED|INT);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ /* This is not optimal but simple. */
+ sp=FIRST_GPR;
+ t1=FIRST_GPR+1;
+ t2=FIRST_GPR+2;
+ f1=FIRST_FPR;
+ f2=FIRST_FPR+1;
+ regsa[t1]=regsa[t2]=1;
+ regsa[f1]=regsa[f2]=1;
+ regsa[sp]=1;
+ regscratch[t1]=regscratch[t2]=0;
+ regscratch[f1]=regscratch[f2]=0;
+ regscratch[sp]=0;
+
+ for(i=FIRST_GPR;i<=LAST_GPR-VOL_GPRS;i++)
+ regscratch[i]=1;
+ for(i=FIRST_FPR;i<=LAST_FPR-VOL_FPRS;i++)
+ regscratch[i]=1;
+ for(i=FIRST_CCR;i<=LAST_CCR-VOL_CCRS;i++)
+ regscratch[i]=1;
+
+ target_macros=marray;
+
+
+ return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+/* A pointer MUST be returned in a register. The code-generator */
+/* has to simulate a pseudo register if necessary. */
+{
+ if(ISFLOAT(t->flags))
+ return FIRST_FPR+2;
+ if(ISSTRUCT(t->flags)||ISUNION(t->flags))
+ return 0;
+ if(zmleq(szof(t),l2zm(4L)))
+ return FIRST_GPR+3;
+ else
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+ register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+ int c=p->code;
+ if(o->flags&VKONST){
+ if(!LOAD_STORE)
+ return 0;
+ if(o==&p->q1&&p->code==ASSIGN&&(p->z.flags&DREFOBJ))
+ return 4;
+ else
+ return 2;
+ }
+ if(o->flags&DREFOBJ)
+ return 4;
+ if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+ if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+ return 2;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(r==0)
+ return 0;
+ t&=NQ;
+ if(t==0&&r>=FIRST_CCR&&r<=LAST_CCR)
+ return 1;
+ if(ISFLOAT(t)&&r>=FIRST_FPR&&r<=LAST_FPR)
+ return 1;
+ if(t==POINTER&&r>=FIRST_GPR&&r<=LAST_GPR)
+ return 1;
+ if(t>=CHAR&&t<=LONG&&r>=FIRST_GPR&&r<=LAST_GPR)
+ return 1;
+ return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* On the PowerPC cpu pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op=o&NQ,tp=t&NQ;
+ if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
+ return 0;
+ if(op==DOUBLE&&tp==LDOUBLE) return 0;
+ if(op==LDOUBLE&&tp==DOUBLE) return 0;
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ if(newobj&§ion!=SPECIAL)
+ emit(f,"%ld\n",zm2l(size));
+ else
+ emit(f,"\t.space\t%ld\n",zm2l(size));
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ if(zm2l(align)>1) emit(f,"\t.align\t2\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;char *sec;
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(v->clist||section==SPECIAL){
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }else
+ emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+ newobj=1;
+ }
+ if(v->storage_class==EXTERN){
+ emit(f,"\t.globl\t%s%s\n",idprefix,v->identifier);
+ if(v->flags&(DEFINED|TENTATIVE)){
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(v->clist||section==SPECIAL){
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ emit(f,"\tdc.%s\t",dt(t&NQ));
+ if(!p->tree){
+ if(ISFLOAT(t)){
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ if((t&NQ)!=FLOAT){
+ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ }else{
+ emitval(f,&p->val,t&NU);
+ }
+ }else{
+ emit_obj(f,&p->tree->o,t&NU);
+ }
+ emit(f,"\n");newobj=0;
+}
+
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/* The main code-generation. */
+{
+ int c,t,i;
+ struct IC *m;
+ argsize=0;
+ if(DEBUG&1) printf("gen_code()\n");
+ for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+ maxpushed=0;
+
+ /*FIXME*/
+ ret="\trts\n";
+
+ for(m=p;m;m=m->next){
+ c=m->code;t=m->typf&NU;
+ if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
+ if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
+
+ /* convert MULT/DIV/MOD with powers of two */
+ if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+ eval_const(&m->q2.val,t);
+ i=pof2(vmax);
+ if(i){
+ if(c==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ m->code=AND;
+ }else{
+ vmax=l2zm(i-1);
+ if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+ }
+ c=m->code;
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ if(c==AND){
+ insert_const(&m->q2.val,t);
+ }else{
+ insert_const(&m->q2.val,INT);
+ p->typf2=INT;
+ }
+ }
+ }
+#if FIXED_SP
+ if(c==CALL&&argsize<zm2l(m->q2.val.vmax)) argsize=zm2l(m->q2.val.vmax);
+#endif
+ }
+ peephole(p);
+
+ for(c=1;c<=MAXR;c++){
+ if(regsa[c]||regused[c]){
+ BSET(regs_modified,c);
+ }
+ }
+
+ localsize=(zm2l(offset)+3)/4*4;
+#if FIXED_SP
+ /*FIXME: adjust localsize to get an aligned stack-frame */
+#endif
+
+ function_top(f,v,localsize);
+ pushed=0;
+
+ for(;p;p=p->next){
+ c=p->code;t=p->typf;
+ if(c==NOP) {p->z.flags=0;continue;}
+ if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
+ if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
+ if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);continue;}
+ if(c==BRA){
+ if(t==exit_label&&framesize==0)
+ emit(f,ret);
+ else
+ emit(f,"\tb\t%s%d\n",labprefix,t);
+ continue;
+ }
+ if(c>=BEQ&&c<BRA){
+ emit(f,"\tb%s\t",ccs[c-BEQ]);
+ if(isreg(q1)){
+ emit_obj(f,&p->q1,0);
+ emit(f,",");
+ }
+ emit(f,"%s%d\n",labprefix,t);
+ continue;
+ }
+ if(c==MOVETOREG){
+ load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+ continue;
+ }
+ if(c==MOVEFROMREG){
+ store_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+ continue;
+ }
+ if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+ ierror(0);
+ }
+ p=preload(f,p);
+ c=p->code;
+ if(c==SUBPFP) c=SUB;
+ if(c==ADDI2P) c=ADD;
+ if(c==SUBIFP) c=SUB;
+ if(c==CONVERT){
+ if(ISFLOAT(q1typ(p))||ISFLOAT(ztyp(p))) ierror(0);
+ if(sizetab[q1typ(p)&NQ]<sizetab[ztyp(p)&NQ]){
+ if(q1typ(p)&UNSIGNED)
+ emit(f,"\tzext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+ else
+ emit(f,"\tsext.%s\t%s\n",dt(q1typ(p)),regnames[zreg]);
+ }
+ save_result(f,p);
+ continue;
+ }
+ if(c==KOMPLEMENT){
+ load_reg(f,zreg,&p->q1,t);
+ emit(f,"\tcpl.%s\t%s\n",dt(t),regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c==SETRETURN){
+ load_reg(f,p->z.reg,&p->q1,t);
+ BSET(regs_modified,p->z.reg);
+ continue;
+ }
+ if(c==GETRETURN){
+ if(p->q1.reg){
+ zreg=p->q1.reg;
+ save_result(f,p);
+ }else
+ p->z.flags=0;
+ continue;
+ }
+ if(c==CALL){
+ int reg;
+ /*FIXME*/
+#if 0
+ if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+ if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+ stack=framesize+zum2ul(p->q1.v->fi->stack1);
+ }else
+ stack_valid=0;
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ }else{
+ emit(f,"\tcall\t");
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ }
+ /*FIXME*/
+#if FIXED_SP
+ pushed-=zm2l(p->q2.val.vmax);
+#endif
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+ bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+ }else{
+ int i;
+ for(i=1;i<=MAXR;i++){
+ if(regscratch[i]) BSET(regs_modified,i);
+ }
+ }
+ continue;
+ }
+ if(c==ASSIGN||c==PUSH){
+ if(t==0) ierror(0);
+ if(c==PUSH){
+#if FIXED_SP
+ emit(f,"\tmov.%s\t%ld(%s),",dt(t),pushed,regnames[sp]);
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ pushed+=zm2l(p->q2.val.vmax);
+#else
+ emit(f,"\tpush.%s\t",dt(t));
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ push(zm2l(p->q2.val.vmax));
+#endif
+ continue;
+ }
+ if(c==ASSIGN){
+ load_reg(f,zreg,&p->q1,t);
+ save_result(f,p);
+ }
+ continue;
+ }
+ if(c==ADDRESS){
+ load_address(f,zreg,&p->q1,POINTER);
+ save_result(f,p);
+ continue;
+ }
+ if(c==MINUS){
+ load_reg(f,zreg,&p->q1,t);
+ emit(f,"\tneg.%s\t%s\n",dt(t),regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c==TEST){
+ emit(f,"\ttst.%s\t",dt(t));
+ if(multiple_ccs)
+ emit(f,"%s,",regnames[zreg]);
+ emit_obj(f,&p->q1,t);
+ emit(f,"\n");
+ if(multiple_ccs)
+ save_result(f,p);
+ continue;
+ }
+ if(c==COMPARE){
+ emit(f,"\tcmp.%s\t",dt(t));
+ if(multiple_ccs)
+ emit(f,"%s,",regnames[zreg]);
+ emit_obj(f,&p->q1,t);
+ emit(f,",");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ if(multiple_ccs)
+ save_result(f,p);
+ continue;
+ }
+ if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)){
+ if(!THREE_ADDR)
+ load_reg(f,zreg,&p->q1,t);
+ if(c>=OR&&c<=AND)
+ emit(f,"\t%s.%s\t%s,",logicals[c-OR],dt(t),regnames[zreg]);
+ else
+ emit(f,"\t%s.%s\t%s,",arithmetics[c-LSHIFT],dt(t),regnames[zreg]);
+ if(THREE_ADDR){
+ emit_obj(f,&p->q1,t);
+ emit(f,",");
+ }
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ save_result(f,p);
+ continue;
+ }
+ pric2(stdout,p);
+ ierror(0);
+ }
+ function_bottom(f,v,localsize);
+ if(stack_valid){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=stack;
+ }
+ emit(f,"# stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");
+}
+
+int shortcut(int code,int typ)
+{
+ return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+ int f;
+ f=t->flags&NQ;
+ if(f<=LONG||f==POINTER){
+ if(m->gregs>=GPR_ARGS)
+ return 0;
+ else
+ return FIRST_GPR+3+m->gregs++;
+ }
+ if(ISFLOAT(f)){
+ if(m->fregs>=FPR_ARGS)
+ return 0;
+ else
+ return FIRST_FPR+2+m->fregs++;
+ }
+ return 0;
+}
+
+int handle_pragma(const char *s)
+{
+}
+void cleanup_cg(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+ if(f) section=-1;
+}
+
diff --git a/machines/src/machine.dt b/machines/src/machine.dt
new file mode 100755
index 0000000..7ece518
--- /dev/null
+++ b/machines/src/machine.dt
@@ -0,0 +1,14 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
diff --git a/machines/src/machine.h b/machines/src/machine.h
new file mode 100755
index 0000000..98a944f
--- /dev/null
+++ b/machines/src/machine.h
@@ -0,0 +1,125 @@
+/* C src backend for vbcc
+*/
+
+/* buil-time configurable options: */
+#define SCHAR_REGS 64
+#define UCHAR_REGS 64
+#define SSHORT_REGS 64
+#define USHORT_REGS 64
+#define SINT_REGS 64
+#define UINT_REGS 64
+#define SLONG_REGS 64
+#define ULONG_REGS 64
+#define SLLONG_REGS 64
+#define ULLONG_REGS 64
+#define FLOAT_REGS 64
+#define DOUBLE_REGS 64
+#define LDOUBLE_REGS 64
+#define POINTER_REGS 64
+
+#include "dt.h"
+
+/* internally used by the backend */
+#define FIRST_SCHAR 1
+#define LAST_SCHAR (FIRST_SCHAR+SCHAR_REGS)
+#define FIRST_UCHAR (LAST_SCHAR+1)
+#define LAST_UCHAR (FIRST_UCHAR+UCHAR_REGS)
+
+#define FIRST_SSHORT (LAST_UCHAR+1)
+#define LAST_SSHORT (FIRST_SSHORT+SSHORT_REGS)
+#define FIRST_USHORT (LAST_SSHORT+1)
+#define LAST_USHORT (FIRST_USHORT+USHORT_REGS)
+
+#define FIRST_SINT (LAST_USHORT+1)
+#define LAST_SINT (FIRST_SINT+SINT_REGS)
+#define FIRST_UINT (LAST_SINT+1)
+#define LAST_UINT (FIRST_UINT+UINT_REGS)
+
+#define FIRST_SLONG (LAST_UINT+1)
+#define LAST_SLONG (FIRST_SLONG+SLONG_REGS)
+#define FIRST_ULONG (LAST_SLONG+1)
+#define LAST_ULONG (FIRST_ULONG+ULONG_REGS)
+
+#define FIRST_SLLONG (LAST_ULONG+1)
+#define LAST_SLLONG (FIRST_SLLONG+SLLONG_REGS)
+#define FIRST_ULLONG (LAST_SLLONG+1)
+#define LAST_ULLONG (FIRST_ULLONG+ULLONG_REGS)
+
+#define FIRST_FLOAT (LAST_ULLONG+1)
+#define LAST_FLOAT (FIRST_FLOAT+FLOAT_REGS)
+
+#define FIRST_DOUBLE (LAST_FLOAT+1)
+#define LAST_DOUBLE (DOUBLE_FLOAT+DOUBLE_REGS)
+
+#define FIRST_LDOUBLE (LAST_DOUBLE+1)
+#define LAST_LDOUBLE (LDOUBLE_FLOAT+LDOUBLE_REGS)
+
+#define FIRST_POINTER (LAST_LDOUBLE+1)
+#define LAST_POINTER (POINTER_FLOAT+POINTER_REGS)
+
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Currently possible are (const,gpr) and (gpr,gpr) */
+struct AddressingMode{
+ int dummy;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR LAST_POINTER
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 20
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 1
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P CHAR
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 1
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 0
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+/* Parameters are sometimes passed in registers without __reg. */
+#define HAVE_REGPARMS 0
+
+/* Parameters on the stack should be pushed in order rather than */
+/* in reverse order. */
+#define ORDERED_PUSH FIXED_SP
+
+/* we only need the standard data types (no bit-types, different pointers
+ etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do not use unsigned int as size_t (but unsigned long, the default) */
+#undef HAVE_INT_SIZET
+
+/* we do not need register-pairs */
+#undef HAVE_REGPAIRS
+
diff --git a/machines/vidcore/machine.c b/machines/vidcore/machine.c
new file mode 100644
index 0000000..420a4d0
--- /dev/null
+++ b/machines/vidcore/machine.c
@@ -0,0 +1,1774 @@
+/* Backend for VideoCore IV
+ (c) in 2013 by Volker Barthelmann
+*/
+
+/* TODO:
+ - extended registers
+ - floating point
+ - long long
+ - memcpy
+ - addcmp
+ - bcc reg
+ - cond. ins
+ - vector
+ - non-pc addressing
+*/
+
+#include "supp.h"
+
+static char FILE_[]=__FILE__;
+
+/* Public data that MUST be there. */
+
+/* Name and copyright. */
+char cg_copyright[]="vbcc VideoCore IV code-generator V0.1 (c) in 2013 by Volker Barthelmann";
+
+/* the flag-name, do not use names beginning with l, L, I, D or U, because
+ they collide with the frontend */
+char *g_flags_name[MAXGF]={"use-commons","use-framepointer",
+ "short-double","one-section",
+ "no-delayed-popping"};
+
+int g_flags[MAXGF]={0,0,
+ 0};
+
+/* the results of parsing the command-line-flags will be stored here */
+union ppi g_flags_val[MAXGF];
+
+/* Alignment-requirements for all types in bytes. */
+zmax align[MAX_TYPE+1];
+
+/* Alignment that is sufficient for every object. */
+zmax maxalign;
+
+/* CHAR_BIT for the target machine. */
+zmax char_bit;
+
+/* sizes of the basic types (in bytes) */
+zmax sizetab[MAX_TYPE+1];
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all registers. will be initialized in init_cg(),
+ register number 0 is invalid, valid registers start at 1 */
+char *regnames[MAXR+1];
+
+/* The Size of each register in bytes. */
+zmax regsize[MAXR+1];
+
+/* a type which can store each register. */
+struct Typ *regtype[MAXR+1];
+
+/* regsa[reg]!=0 if a certain register is allocated and should */
+/* not be used by the compiler pass. */
+int regsa[MAXR+1];
+
+/* Specifies which registers may be scratched by functions. */
+int regscratch[MAXR+1];
+
+/* specifies the priority for the register-allocator, if the same
+ estimated cost-saving can be obtained by several registers, the
+ one with the highest priority will be used */
+int reg_prio[MAXR+1];
+
+/* an empty reg-handle representing initial state */
+struct reg_handle empty_reg_handle={0};
+
+/* Names of target-specific variable attributes. */
+char *g_attr_name[]={"__interrupt",0};
+
+
+/****************************************/
+/* Private data and functions. */
+/****************************************/
+
+/* addressing modes */
+#define AM_IMM_IND 1
+#define AM_GPR_IND 2
+#define AM_POSTINC 3
+#define AM_PREDEC 4
+
+#define USE_COMMONS (g_flags[0]&USEDFLAG)
+#define USE_FP (g_flags[1]&USEDFLAG)
+#define SHORT_DOUBLE (g_flags[2]&USEDFLAG)
+#define ONESEC (g_flags[3]&USEDFLAG)
+#define NODELAYEDPOP (g_flags[4]&USEDFLAG)
+
+
+/* alignment of basic data-types, used to initialize align[] */
+static long malign[MAX_TYPE+1]= {1,1,2,4,4,4,4,8,8,1,4,1,1,1,4,1};
+/* sizes of basic data-types, used to initialize sizetab[] */
+static long msizetab[MAX_TYPE+1]={1,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
+
+/* used to initialize regtyp[] */
+static struct Typ ltyp={LONG},ldbl={DOUBLE},lchar={CHAR};
+
+/* macros defined by the backend */
+static char *marray[]={"__section(x)=__vattr(\"section(\"#x\")\")",
+ "__VIDEOCORE__",
+ 0, /* __SHORT_DOUBLE__ */
+ 0};
+
+/* special registers */
+enum{
+ r0=1,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,
+ r16,r17,r18,r19,r20,r21,r22,r23,r24,r25,r26,r27,r28,r29,r30,r31,
+ r0r1,r2r3,r4r5,r6r7,r8r9,r10r11,r12r13,r14r15,
+ r16r17,r18r19,r20r21,r22r23,r24r25,r26r27,r28r29,r30r31
+};
+
+static int sd=r24;
+static int sp=r25;
+static int lr=r26;
+static int sr=r30;
+static int pc=r31;
+static int t1=r15;
+static int t2=r14;
+
+static int last_saved;
+
+#define dt(t) (((t)&UNSIGNED)?udt[(t)&NQ]:sdt[(t)&NQ])
+#define sdt(t) (udt[(t)&NQ])
+static char *sdt[MAX_TYPE+1]={"??","b","hs","","","ll","","d","ld","v",""};
+static char *udt[MAX_TYPE+1]={"??","b","h","","","ull","","d","ld","v",""};
+
+static char *dct[]={"","byte","2byte","4byte","4byte","4byte","4byte","4byte","4byte"};
+
+static int no_suffix;
+
+/* sections */
+#define DATA 0
+#define BSS 1
+#define CODE 2
+#define RODATA 3
+#define SPECIAL 4
+
+static long stack;
+static int stack_valid;
+static int section=-1,newobj;
+static char *codename="\t.text\n",
+ *dataname="\t.data\n",
+ *bssname="",
+ *rodataname="\t.section\t.rodata\n";
+
+/* conditional execution */
+static char *cc;
+
+/* return-instruction */
+static char *ret;
+
+/* label at the end of the function (if any) */
+static int exit_label;
+
+/* assembly-prefixes for labels and external identifiers */
+static char *labprefix="l",*idprefix="_";
+
+#if 0
+/* variables to calculate the size and partitioning of the stack-frame
+ in the case of FIXED_SP */
+static long frameoffset,pushed,maxpushed,framesize;
+#else
+/* variables to keep track of the current stack-offset in the case of
+ a moving stack-pointer */
+static long notpopped,dontpop,stackoffset,maxpushed;
+#endif
+
+static long localsize,rsavesize,argsize;
+
+static void emit_obj(FILE *f,struct obj *p,int t);
+
+/* calculate the actual current offset of an object relativ to the
+ stack-pointer; we use a layout like this:
+ ------------------------------------------------
+ | arguments to this function |
+ ------------------------------------------------
+ | return-address [size=4] |
+ ------------------------------------------------
+ | caller-save registers [size=rsavesize] |
+ ------------------------------------------------
+ | local variables [size=localsize] |
+ ------------------------------------------------
+ | arguments to called functions [size=argsize] |
+ ------------------------------------------------
+ All sizes will be aligned as necessary.
+ In the case of FIXED_SP, the stack-pointer will be adjusted at
+ function-entry to leave enough space for the arguments and have it
+ aligned to 16 bytes. Therefore, when calling a function, the
+ stack-pointer is always aligned to 16 bytes.
+ For a moving stack-pointer, the stack-pointer will usually point
+ to the bottom of the area for local variables, but will move while
+ arguments are put on the stack.
+
+ This is just an example layout. Other layouts are also possible.
+*/
+
+static void push(long l)
+{
+ stackoffset-=l;
+ if(stackoffset<maxpushed)
+ maxpushed=stackoffset;
+ if(-maxpushed>stack)
+ stack=-maxpushed;
+}
+
+static void pop(long l)
+{
+ stackoffset+=l;
+}
+
+static long real_offset(struct obj *o)
+{
+ long off=zm2l(o->v->offset);
+ if(off<0){
+ /* function parameter */
+ off=localsize+rsavesize-off-zm2l(maxalign);
+ }
+
+ off-=stackoffset;
+
+ off+=zm2l(o->val.vmax);
+ return off;
+}
+
+/* Initializes an addressing-mode structure and returns a pointer to
+ that object. Will not survive a second call! */
+static struct obj *cam(int flags,int base,long offset)
+{
+ static struct obj obj;
+ static struct AddressingMode am;
+ obj.am=&am;
+ am.flags=flags;
+ am.base=base;
+ am.offset=offset;
+ return &obj;
+}
+
+/* changes to a special section, used for __section() */
+static int special_section(FILE *f,struct Var *v)
+{
+ char *sec;
+ if(!v->vattr) return 0;
+ sec=strstr(v->vattr,"section(");
+ if(!sec) return 0;
+ sec+=strlen("section(");
+ emit(f,"\t.section\t");
+ while(*sec&&*sec!=')') emit_char(f,*sec++);
+ emit(f,"\n");
+ if(f) section=SPECIAL;
+ return 1;
+}
+
+static unsigned long pushmask;
+
+static int ic_uses_reg(struct IC *p,int r,int onlyuses)
+{
+ if(reg_pair(r,&rp)){
+ return ic_uses_reg(p,rp.r1,onlyuses)||ic_uses_reg(p,rp.r2,onlyuses);
+ }
+ /*FIXME: handle regpairs */
+ if((p->q1.flags®)&&p->q1.reg==r) return 1;
+ if((p->q2.flags®)&&p->q2.reg==r) return 1;
+ if(onlyuses){
+ if((p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->z.reg==r) return 1;
+ }else{
+ if((p->z.flags®)&&p->z.reg==r) return 1;
+ }
+ if(p->q1.am){
+ if(p->q1.am->base==r) return 1;
+ if(p->q1.am->flags==AM_GPR_IND&&p->q1.am->offset==r) return 1;
+ }
+ if(p->q2.am){
+ if(p->q2.am->base==r) return 1;
+ if(p->q2.am->flags==AM_GPR_IND&&p->q2.am->offset==r) return 1;
+ }
+ if(p->z.am){
+ if(p->z.am->base==r) return 1;
+ if(p->z.am->flags==AM_GPR_IND&&p->z.am->offset==r) return 1;
+ }
+ return 0;
+}
+
+static int reg_is_scratched(struct IC *p,int r)
+{
+ for(p=p->next;p;p=p->next){
+ int c=p->code;
+ if(c>=LABEL&&c<=BRA)
+ return 0;
+ if(c==FREEREG&&p->q1.reg==r)
+ return 1;
+ if(ic_uses_reg(p,r,1))
+ return 0;
+ if((p->q1.flags&(REG|DREFOBJ))==REG&&p->z.reg==r)
+ return 1;
+ }
+ return 0;
+}
+
+static int get_reg(FILE *f,struct IC *p)
+{
+ int r;
+ for(r=r0;r<=r31;r++){
+ if(!regs[r]&®used[r]&&!ic_uses_reg(p,r,0)){
+ regs[r]=1;
+ return r;
+ }
+ }
+ for(r=r0;r<=r31;r++){
+ if(!regs[r]&&!ic_uses_reg(p,r,0)){
+ regs[r]=1;
+ return r;
+ }
+ }
+ for(r=r0;r<=r31;r++){
+ if(!ic_uses_reg(p,r,0))
+ break;
+ }
+ argsize+=4;
+ emit(f,"\tst\t%s,--(%s)\n",regnames[r],regnames[sp]);
+ push(4);
+ pushmask|=(1<<(r-1));
+ regs[r]=1;
+ return r;
+}
+
+static void free_reg(FILE *f,int r)
+{
+ if(pushmask&(1<<(r-1))){
+ emit(f,"\tld\t%s,(%s)++\n",regnames[r],regnames[sp]);
+ pop(4);
+ argsize-=4;
+ }else
+ regs[r]=0;
+ pushmask&=~(1<<(r-1));
+}
+
+/* generate code to load the address of a variable into register r */
+static void load_address(FILE *f,int r,struct obj *o,int type)
+/* Generates code to load the address of a variable into register r. */
+{
+ if(!(o->flags&VAR)) ierror(0);
+ if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
+ long off=real_offset(o);
+ emit(f,"\tadd%s\t%s,%s,%ld\n",cc,regnames[r],regnames[sp],off);
+ }else{
+ emit(f,"\tlea%s\t%s,",cc,regnames[r]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }
+}
+/* Generates code to load a memory object into register r. tmp is a
+ general purpose register which may be used. tmp can be r. */
+static void load_reg(FILE *f,int r,struct obj *o,int type)
+{
+ type&=NU;
+ if(reg_pair(r,&rp)) ierror(0);
+ if(o->flags&VARADR){
+ load_address(f,r,o,POINTER);
+ }else if(o->flags&KONST){
+ emit(f,"\tmov%s\t%s,",cc,regnames[r]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }else{
+ if((o->flags&(REG|DREFOBJ))==REG){
+ if(o->reg!=r)
+ emit(f,"\tmov%s\t%s,%s\n",cc,regnames[r],regnames[o->reg]);
+ }else{
+ if(SHORT_DOUBLE&&ISFLOAT(type)) type=FLOAT;
+ emit(f,"\tld%s%s\t%s,",dt(type),cc,regnames[r]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+ }
+ }
+}
+
+/* Generates code to store register r into memory object o. */
+static void store_reg(FILE *f,int r,struct obj *o,int type)
+{
+ if(reg_pair(r,&rp)) ierror(0);
+ type&=NQ;
+ if(SHORT_DOUBLE&&ISFLOAT(type)) type=FLOAT;
+ emit(f,"\tst%s%s\t%s,",sdt(type),cc,regnames[r]);
+ emit_obj(f,o,type);
+ emit(f,"\n");
+}
+
+/* Yields log2(x)+1 or 0. */
+static long pof2(zumax x)
+{
+ zumax p;int ln=1;
+ p=ul2zum(1L);
+ while(ln<=32&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+
+static struct IC *preload(FILE *,struct IC *);
+
+static void function_top(FILE *,struct Var *,long);
+static void function_bottom(FILE *f,struct Var *,long);
+
+#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
+#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)
+
+static int q1reg,q2reg,zreg;
+
+static char *ccs[]={"eq","ne","lt","ge","le","gt",""};
+static char *ccu[]={"eq","ne","cs","cc","ls","hi",""};
+static char *logicals[]={"or","eor","and"};
+static char *arithmetics[]={"lsl","asr","add","sub","mul","divs","mod"};
+static char *uarithmetics[]={"lsl","lsr","add","sub","mul","divu","mod"};
+static char *farithmetics[]={"--","--","fadd","fsub","fmul","fdiv","--"};
+
+
+/* Does some pre-processing like fetching operands from memory to
+ registers etc. */
+static struct IC *preload(FILE *f,struct IC *p)
+{
+ int r,load;
+
+ if(isreg(q1))
+ q1reg=p->q1.reg;
+ else
+ q1reg=0;
+
+ if(isreg(q2))
+ q2reg=p->q2.reg;
+ else
+ q2reg=0;
+
+ if(isreg(z)){
+ zreg=p->z.reg;
+ }else{
+ zreg=t1;
+ }
+
+ if((p->q1.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q1.am){
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,t1,&p->q1,POINTER);
+ p->q1.reg=t1;
+ p->q1.flags|=(REG|DREFOBJ);
+ }
+ if(p->q1.flags&&!isreg(q1)&&p->code!=ASSIGN&&p->code!=PUSH&&p->code!=SETRETURN/*&&!(p->q1.flags&KONST)*/){
+ q1reg=zreg;
+ load_reg(f,q1reg,&p->q1,q1typ(p));
+ p->q1.reg=q1reg;
+ p->q1.flags=REG;
+ }
+
+ if((p->q2.flags&(DREFOBJ|REG))==DREFOBJ&&!p->q2.am){
+ p->q2.flags&=~DREFOBJ;
+ load_reg(f,t2,&p->q2,POINTER);
+ p->q2.reg=t2;
+ p->q2.flags|=(REG|DREFOBJ);
+ }
+
+ if(p->q2.flags){
+ load=1;
+ if(isreg(q2)) load=0;
+ if((p->q2.flags&KONST)&&!ISFLOAT(p->typf)&&(p->code==ADD||p->code==SUB||p->code==ADDI2P||p->code==COMPARE||p->code==SUBIFP||p->code==SUBPFP))
+ load=0;
+ if(p->code>=OR&&p->code<=MOD&&(p->q2.flags&KONST)&&!ISFLOAT(p->typf)){
+ unsigned long v;
+ eval_const(&p->q2.val,q2typ(p));
+ v=zum2ul(vumax);
+ if(v<=31) load=0;
+ }
+ if(load){
+ q2reg=t2;
+ load_reg(f,q2reg,&p->q2,q2typ(p));
+ p->q2.reg=q2reg;
+ p->q2.flags=REG;
+ }
+ }
+ return p;
+}
+
+/* save the result (in zreg) into p->z */
+void save_result(FILE *f,struct IC *p)
+{
+ if((p->z.flags&(REG|DREFOBJ))==DREFOBJ&&!p->z.am){
+ p->z.flags&=~DREFOBJ;
+ load_reg(f,t2,&p->z,POINTER);
+ p->z.reg=t2;
+ p->z.flags|=(REG|DREFOBJ);
+ }
+ if(isreg(z)){
+ if(p->z.reg!=zreg)
+ emit(f,"\tmov%s\t%s,%s\n",cc,regnames[p->z.reg],regnames[zreg]);
+ }else{
+ store_reg(f,zreg,&p->z,ztyp(p));
+ }
+}
+
+/* prints an object */
+static void emit_obj(FILE *f,struct obj *p,int t)
+{
+ if((p->flags&DREFOBJ)&&p->am){
+ if(p->am->flags==AM_GPR_IND) emit(f,"(%s,%s)",regnames[p->am->base],regnames[p->am->offset]);
+ if(p->am->flags==AM_IMM_IND) emit(f,"%ld(%s)",p->am->offset,regnames[p->am->base]);
+ if(p->am->flags==AM_POSTINC) emit(f,"(%s)++",regnames[p->am->base]);
+ if(p->am->flags==AM_PREDEC) emit(f,"--(%s)",regnames[p->am->base]);
+ return;
+ }
+ if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ emitval(f,&p->val,p->dtyp&NU);
+ return;
+ }
+ if(p->flags&DREFOBJ) emit(f,"(");
+ if(p->flags®){
+ emit(f,"%s",regnames[p->reg]);
+ }else if(p->flags&VAR) {
+ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER)
+ emit(f,"%ld(%s)",real_offset(p),regnames[sp]);
+ else{
+ if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,LONG);emit(f,"+");}
+ if(p->v->storage_class==STATIC){
+ emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
+ }else{
+ emit(f,"%s%s",idprefix,p->v->identifier);
+ }
+ if(!no_suffix)
+ emit(f,"(%s)",regnames[pc]);
+ }
+ }
+ if(p->flags&KONST){
+ if(ISFLOAT(t)){
+ unsigned char *ip;
+ eval_const(&p->val,t);
+ ip=(unsigned char *)&vfloat;
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ }else
+ emitval(f,&p->val,t&NU);
+ }
+ if(p->flags&DREFOBJ) emit(f,")");
+}
+
+/* Test if there is a sequence of FREEREGs containing FREEREG reg.
+ Used by peephole. */
+static int exists_freereg(struct IC *p,int reg)
+{
+ while(p&&(p->code==FREEREG||p->code==ALLOCREG)){
+ if(p->code==FREEREG&&p->q1.reg==reg) return 1;
+ p=p->next;
+ }
+ return 0;
+}
+
+/* search for possible addressing-modes */
+static void peephole(struct IC *p)
+{
+ int c,c2,r;struct IC *p2;struct AddressingMode *am;
+
+ for(;p;p=p->next){
+ c=p->code;
+ if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
+ if(c==LABEL) exit_label=p->typf;
+
+ /* -(ax) */
+ if(c==SUBIFP&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg&&p->q1.reg<=8&&isconst(q2)){
+ zmax sz;
+ int t;
+ r=p->q1.reg;
+ eval_const(&p->q2.val,q2typ(p));
+ sz=zm2l(vmax);
+ if(sz==1||sz==2||sz==4){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r&&(!(p2->q2.flags®)||p2->q2.reg!=r)&&(!(p2->z.flags®)||p2->z.reg!=r)&&(
+c2!=CONVERT||(q1typ(p2)&NQ)<=(ztyp(p2)&NQ))){
+ t=(q1typ(p2)&NQ);
+ if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[q1typ(p2)&NQ],l2zm(sz))){
+ p2->q1.am=am=mymalloc(sizeof(*am));
+ p2->q1.val.vmax=l2zm(0L);
+ am->base=r;
+ am->flags=AM_PREDEC;
+ p->code=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ break;
+ }
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r&&(!(p2->q1.flags®)||p2->q1.reg!=r)&&(!(p2->z.flags®)||p2->z.reg!=r)){
+ t=(q2typ(p2)&NQ);
+ if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[q2typ(p2)&NQ],l2zm(sz))){
+ p2->q2.am=am=mymalloc(sizeof(*am));
+ p2->q2.val.vmax=l2zm(0L);
+ am->base=r;
+ am->flags=AM_PREDEC;
+ p->code=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ break;
+ }
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r&&(!(p2->q2.flags®)||p2->q2.reg!=r)&&(!(p2->q1.flags®)||p2->q1.reg!=r)){
+ t=(ztyp(p2)&NQ);
+ if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[ztyp(p2)&NQ],l2zm(sz))){
+ p2->z.am=am=mymalloc(sizeof(*am));
+ p2->z.val.vmax=l2zm(0L);
+ am->base=r;
+ am->flags=AM_PREDEC;
+ p->code=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ break;
+ }
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if((p2->q1.flags®)&&p2->q1.reg==r) break;
+ if((p2->q2.flags®)&&p2->q2.reg==r) break;
+ if((p2->z.flags®)&&p2->z.reg==r) break;
+ }
+ }
+ }
+
+ /* (ax)+ in q1 */
+ if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&(c!=CONVERT||(q1typ(p)&NQ)<=(ztyp(p)&NQ))){
+ int t=(q1typ(p)&NQ);
+ long sz=zm2l(sizetab[t]);
+ r=p->q1.reg;
+ if((sz==1||sz==2||sz==4)&&(ISINT(t)||ISPOINTER(t)||ISFLOAT(t))&&(!(p->q2.flags®)||p->q2.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,q2typ(p2));
+ if(zmeqto(vmax,l2zm(sz))){
+ p->q1.am=am=mymalloc(sizeof(*am));
+ p->q1.val.vmax=l2zm(0L);
+ am->flags=AM_POSTINC;
+ am->base=r;
+ am->offset=0;
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ break;
+ }
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if((p2->q1.flags®)&&p2->q1.reg==r) break;
+ if((p2->q2.flags®)&&p2->q2.reg==r) break;
+ if((p2->z.flags®)&&p2->z.reg==r) break;
+ }
+ }
+ }
+ /* (ax)+ in q2 */
+ if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&(c!=CONVERT||(q2typ(p)&NQ)<=(ztyp(p)&NQ))){
+ int t=(q2typ(p)&NQ);
+ long sz=zm2l(sizetab[t]);
+ r=p->q2.reg;
+ if((sz==1||sz==2||sz==4)&&(ISINT(t)||ISPOINTER(t)||ISFLOAT(t))&&(!(p->q1.flags®)||p->q1.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,q2typ(p2));
+ if(zmeqto(vmax,l2zm(sz))){
+ p->q2.am=am=mymalloc(sizeof(*am));
+ p->q2.val.vmax=l2zm(0L);
+ am->flags=AM_POSTINC;
+ am->base=r;
+ am->offset=0;
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ break;
+ }
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if((p2->q1.flags®)&&p2->q1.reg==r) break;
+ if((p2->q2.flags®)&&p2->q2.reg==r) break;
+ if((p2->z.flags®)&&p2->z.reg==r) break;
+ }
+ }
+ }
+ /* (ax)+ in z */
+ if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->z.reg<=8&&(c!=CONVERT||(q2typ(p)&NQ)<=(ztyp(p)&NQ))){
+ int t=(ztyp(p)&NQ);
+ long sz=zm2l(sizetab[t]);
+ r=p->z.reg;
+ if((sz==1||sz==2||sz==4)&&(ISINT(t)||ISPOINTER(t)||ISFLOAT(t))&&(!(p->q1.flags®)||p->q1.reg!=r)&&(!(p->q2.flags®)||p->q2.reg!=r)){
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p2->q2.val,q2typ(p2));
+ if(zmeqto(vmax,l2zm(sz))){
+ p->z.am=am=mymalloc(sizeof(*am));
+ p->z.val.vmax=l2zm(0L);
+ am->flags=AM_POSTINC;
+ am->base=r;
+ am->offset=0;
+ p2->code=NOP;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ break;
+ }
+ }
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if((p2->q1.flags®)&&p2->q1.reg==r) break;
+ if((p2->q2.flags®)&&p2->q2.reg==r) break;
+ if((p2->z.flags®)&&p2->z.reg==r) break;
+ }
+ }
+ }
+ /* Try const(reg) */
+ if((c==ADDI2P/*||c==SUBIFP*/)&&isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+ int base;zmax of;struct obj *o;
+ eval_const(&p->q2.val,p->typf);
+ if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
+ if(1/*zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L))*/){
+ r=p->z.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if((c2==ASSIGN||c2==PUSH)&&(!ISSCALAR(p2->typf)||!zmeqto(p2->q2.val.vmax,sizetab[p2->typf&NQ]))){
+ if((p->q1.flags®)&&p->q1.reg==base)
+ break;
+ if((p->z.flags®)&&p->z.reg==base)
+ break;
+ }
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=AM_IMM_IND;
+ am->base=base;
+ am->offset=zm2l(of);
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+ /* Try reg,reg */
+ if(c==ADDI2P&&isreg(q2)&&isreg(z)&&(isreg(q1)||p->q2.reg!=p->z.reg)){
+ int base,idx;struct obj *o;
+ r=p->z.reg;idx=p->q2.reg;
+ if(isreg(q1)) base=p->q1.reg; else base=r;
+ o=0;
+ for(p2=p->next;p2;p2=p2->next){
+ c2=p2->code;
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+ if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
+ if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
+ if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
+
+ if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
+ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
+ if(o||(q1typ(p2)&NQ)!=CHAR) break;
+ o=&p2->q1;
+ }
+ if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
+ if(o||(q2typ(p2)&NQ)!=CHAR) break;
+ o=&p2->q2;
+ }
+ if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
+ if(o||(ztyp(p2)&NQ)!=CHAR) break;
+ o=&p2->z;
+ }
+ }
+ if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
+ int m;
+ if(c2==FREEREG)
+ m=p2->q1.reg;
+ else
+ m=p2->z.reg;
+ if(m==r){
+ if(o){
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=AM_GPR_IND;
+ am->base=base;
+ am->offset=idx;
+ if(isreg(q1)){
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ }else{
+ p->code=c=ASSIGN;p->q2.flags=0;
+ p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
+ }
+ }
+ break;
+ }
+ if(c2!=FREEREG&&m==base) break;
+ continue;
+ }
+ }
+ }
+ }
+}
+
+/* generates the function entry code */
+static void function_top(FILE *f,struct Var *v,long offset)
+{
+ int i;
+ rsavesize=0;
+ if(!special_section(f,v)&§ion!=CODE){emit(f,codename);if(f) section=CODE;}
+ emit(f,"\t.align\t1\n");
+ if(v->storage_class==EXTERN){
+ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ last_saved=0;
+ for(i=r6;i<t2;i++){
+ if(regused[i])
+ last_saved=i;
+ }
+ if(last_saved){
+ emit(f,"\tpush\t%s-%s",regnames[r6],regnames[last_saved]);
+ rsavesize=(last_saved-r6+1)*4;
+ if(function_calls){
+ emit(f,",lr");
+ rsavesize+=4;
+ }
+ emit(f,"\n");
+ }else if(function_calls){
+ emit(f,"\tpush\t%s-%s,lr\n",regnames[r6],regnames[r6]);
+ rsavesize+=8;
+ }
+ if(offset){
+ emit(f,"\tsub\t%s,%ld\n",regnames[sp],offset);
+ }
+}
+/* generates the function exit code */
+static void function_bottom(FILE *f,struct Var *v,long offset)
+{
+ if(offset){
+ emit(f,"\tadd\t%s,%ld\n",regnames[sp],offset);
+ }
+ if(last_saved){
+ emit(f,"\tpop\t%s-%s",regnames[r6],regnames[last_saved]);
+ if(function_calls){
+ emit(f,",pc");
+ }
+ emit(f,"\n");
+ }else if(function_calls){
+ emit(f,"\tpop\t%s-%s,pc\n",regnames[r6],regnames[r6]);
+ }
+ if(!function_calls)
+ emit(f,ret);
+}
+
+/****************************************/
+/* End of private data and functions. */
+/****************************************/
+
+/* Does necessary initializations for the code-generator. Gets called */
+/* once at the beginning and should return 0 in case of problems. */
+int init_cg(void)
+{
+ int i;
+ /* Initialize some values which cannot be statically initialized */
+ /* because they are stored in the target's arithmetic. */
+ maxalign=l2zm(4L);
+ char_bit=l2zm(8L);
+ stackalign=l2zm(4);
+
+ for(i=0;i<=MAX_TYPE;i++){
+ sizetab[i]=l2zm(msizetab[i]);
+ align[i]=l2zm(malign[i]);
+ }
+
+ if(SHORT_DOUBLE){
+ sizetab[DOUBLE]=sizetab[FLOAT];
+ align[DOUBLE]=align[FLOAT];
+ sizetab[LDOUBLE]=sizetab[FLOAT];
+ align[LDOUBLE]=align[FLOAT];
+ }
+
+ regnames[0]="noreg";
+ for(i=1;i<=32;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"r%d",i-1);
+ regsize[i]=l2zm(4L);
+ regtype[i]=<yp;
+ }
+ for(i=33;i<=48;i++){
+ regnames[i]=mymalloc(10);
+ sprintf(regnames[i],"r%d/r%d",i-33,i-32);
+ regsize[i]=l2zm(8L);
+ regtype[i]=&ldbl;
+ }
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LONG]=t_min(INT);
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=ul2zum(2147483647UL);
+ t_max[LONG]=t_max(INT);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=ul2zum(4294967295UL);
+ tu_max[LONG]=t_max(UNSIGNED|INT);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ /* Reserve a few registers for use by the code-generator. */
+ /* This is not optimal but simple. */
+ regsa[t1]=regsa[t2]=1;
+ regsa[pc]=regsa[lr]=regsa[sp]=regsa[sr]=1;
+ regscratch[t1]=regscratch[t2]=0;
+ regscratch[pc]=regscratch[lr]=regscratch[sp]=regscratch[sr]=1;
+
+ for(i=r16;i<=r31;i++)
+ regscratch[i]=regsa[i]=1;
+
+ for(i=1;i<=6;i++)
+ regscratch[i]=1;
+
+ if(ONESEC){
+ bssname=codename;
+ dataname=codename;
+ rodataname=codename;
+ }
+
+ if(SHORT_DOUBLE) marray[2]="__SHORT_DOUBLE__=1";
+ target_macros=marray;
+
+
+ declare_builtin("__mulint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+ declare_builtin("__addint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+ declare_builtin("__subint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+ declare_builtin("__andint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+ declare_builtin("__orint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+ declare_builtin("__eorint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+ declare_builtin("__negint64",LLONG,LLONG,r0r1,0,0,1,0);
+ declare_builtin("__lslint64",LLONG,LLONG,r0r1,INT,r2,1,0);
+
+ declare_builtin("__divsint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+ declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,r0r1,UNSIGNED|LLONG,r2r3,1,0);
+ declare_builtin("__modsint64",LLONG,LLONG,r0r1,LLONG,r2r3,1,0);
+ declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,r0r1,UNSIGNED|LLONG,r2r3,1,0);
+ declare_builtin("__lsrsint64",LLONG,LLONG,r0r1,INT,r2,1,0);
+ declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,r0r1,INT,r2,1,0);
+ declare_builtin("__cmpsint64",INT,LLONG,r0r1,LLONG,r2r3,1,0);
+ declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,r0r1,UNSIGNED|LLONG,r2r3,1,0);
+ declare_builtin("__sint64toflt32",FLOAT,LLONG,r0r1,0,0,1,0);
+ declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,r0r1,0,0,1,0);
+ declare_builtin("__sint64toflt64",LDOUBLE,LLONG,r0r1,0,0,1,0);
+ declare_builtin("__uint64toflt64",LDOUBLE,UNSIGNED|LLONG,r0r1,0,0,1,0);
+ declare_builtin("__flt32tosint64",LLONG,FLOAT,r0,0,0,1,0);
+ declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,r0,0,0,1,0);
+ declare_builtin("__flt64tosint64",LLONG,LDOUBLE,r0r1,0,0,1,0);
+ declare_builtin("__flt64touint64",UNSIGNED|LLONG,LDOUBLE,r0r1,0,0,1,0);
+
+ declare_builtin("__flt32toflt64",LDOUBLE,FLOAT,r0,0,0,1,0);
+ declare_builtin("__flt64toflt32",FLOAT,LDOUBLE,r0r1,0,0,1,0);
+
+ declare_builtin("__addflt64",LDOUBLE,LDOUBLE,r0r1,LDOUBLE,r2r3,1,0);
+ declare_builtin("__subflt64",LDOUBLE,LDOUBLE,r0r1,LDOUBLE,r2r3,1,0);
+ declare_builtin("__mulflt64",LDOUBLE,LDOUBLE,r0r1,LDOUBLE,r2r3,1,0);
+ declare_builtin("__divflt64",LDOUBLE,LDOUBLE,r0r1,LDOUBLE,r2r3,1,0);
+ declare_builtin("__negflt64",LDOUBLE,LDOUBLE,r0r1,LDOUBLE,r2r3,1,0);
+ declare_builtin("__cmpflt64",INT,LDOUBLE,r0r1,LDOUBLE,r2r3,1,0);
+
+
+ return 1;
+}
+
+void init_db(FILE *f)
+{
+}
+
+int freturn(struct Typ *t)
+/* Returns the register in which variables of type t are returned. */
+/* If the value cannot be returned in a register returns 0. */
+/* A pointer MUST be returned in a register. The code-generator */
+/* has to simulate a pseudo register if necessary. */
+{
+ if(SHORT_DOUBLE&&ISFLOAT(t->flags)) return r0;
+ if(ISSTRUCT(t->flags)||ISUNION(t->flags))
+ return 0;
+ if(zmleq(szof(t),l2zm(4L)))
+ return r0;
+ if(zmeqto(szof(t),l2zm(8L)))
+ return r0r1;
+ return 0;
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ if(r>=r0r1&&r<=r30r31){
+ p->r1=(r-r0r1)*2+r0;
+ p->r2=(r-r0r1)*2+r1;
+ return 1;
+ }
+ return 0;
+}
+
+/* estimate the cost-saving if object o from IC p is placed in
+ register r */
+int cost_savings(struct IC *p,int r,struct obj *o)
+{
+ int c=p->code;
+ if(o->flags&VKONST){
+ return 0;
+ }
+ if(o->flags&DREFOBJ)
+ return 4;
+ if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
+ if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
+ return 2;
+}
+
+int regok(int r,int t,int mode)
+/* Returns 0 if register r cannot store variables of */
+/* type t. If t==POINTER and mode!=0 then it returns */
+/* non-zero only if the register can store a pointer */
+/* and dereference a pointer to mode. */
+{
+ if(r==0)
+ return 0;
+ t&=NQ;
+ if(ISINT(t)||ISFLOAT(t)||ISPOINTER(t)){
+ if(zmeqto(sizetab[t],l2zm(8L))){
+ if(r>=r0r1&&r<=r30r31)
+ return 1;
+ else
+ return 0;
+ }
+ if(r>=r0&&r<=r31)
+ return 1;
+ else
+ return 0;
+ }
+ return 0;
+}
+
+int dangerous_IC(struct IC *p)
+/* Returns zero if the IC p can be safely executed */
+/* without danger of exceptions or similar things. */
+/* vbcc may generate code in which non-dangerous ICs */
+/* are sometimes executed although control-flow may */
+/* never reach them (mainly when moving computations */
+/* out of loops). */
+/* Typical ICs that generate exceptions on some */
+/* machines are: */
+/* - accesses via pointers */
+/* - division/modulo */
+/* - overflow on signed integer/floats */
+{
+ int c=p->code;
+ if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
+ return 1;
+ if((c==DIV||c==MOD)&&!isconst(q2))
+ return 1;
+ return 0;
+}
+
+int must_convert(int o,int t,int const_expr)
+/* Returns zero if code for converting np to type t */
+/* can be omitted. */
+/* On the VideCore IV pointers and 32bit */
+/* integers have the same representation and can use */
+/* the same registers. */
+{
+ int op=o&NQ,tp=t&NQ;
+ if(SHORT_DOUBLE){
+ if(op==DOUBLE||op==LDOUBLE) op=FLOAT;
+ if(tp==DOUBLE||tp==LDOUBLE) tp=FLOAT;
+ }
+ if((op==INT||op==LONG||op==POINTER)&&(tp==INT||tp==LONG||tp==POINTER))
+ return 0;
+ if(op==FLOAT&&tp==FLOAT) return 0;
+ if(op==DOUBLE&&tp==LDOUBLE) return 0;
+ if(op==LDOUBLE&&tp==DOUBLE) return 0;
+ return 1;
+}
+
+void gen_ds(FILE *f,zmax size,struct Typ *t)
+/* This function has to create <size> bytes of storage */
+/* initialized with zero. */
+{
+ if(newobj&&!ONESEC&§ion!=SPECIAL)
+ emit(f,"%ld\n",zm2l(size));
+ else
+ emit(f,"\t.space\t%ld\n",zm2l(size));
+ newobj=0;
+}
+
+void gen_align(FILE *f,zmax align)
+/* This function has to make sure the next data is */
+/* aligned to multiples of <align> bytes. */
+{
+ if(zm2l(align)>1) emit(f,"\t.align\t2\n");
+}
+
+void gen_var_head(FILE *f,struct Var *v)
+/* This function has to create the head of a variable */
+/* definition, i.e. the label and information for */
+/* linkage etc. */
+{
+ int constflag;char *sec;
+ if(v->clist) constflag=is_const(v->vtyp);
+ if(v->storage_class==STATIC){
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(v->clist||ONESEC||section==SPECIAL){
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
+ }else
+ emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
+ newobj=1;
+ }
+ if(v->storage_class==EXTERN){
+ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
+ if(v->flags&(DEFINED|TENTATIVE)){
+ if(!special_section(f,v)){
+ if(v->clist&&(!constflag||(g_flags[2]&USEDFLAG))&§ion!=DATA){emit(f,dataname);if(f) section=DATA;}
+ if(v->clist&&constflag&&!(g_flags[2]&USEDFLAG)&§ion!=RODATA){emit(f,rodataname);if(f) section=RODATA;}
+ if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;}
+ }
+ if(v->clist||ONESEC||section==SPECIAL){
+ gen_align(f,falign(v->vtyp));
+ emit(f,"%s%s:\n",idprefix,v->identifier);
+ }else
+ emit(f,"\t.%scomm\t%s%s,",(USE_COMMONS?"":"l"),idprefix,v->identifier);
+ newobj=1;
+ }
+ }
+}
+
+void gen_dc(FILE *f,int t,struct const_list *p)
+/* This function has to create static storage */
+/* initialized with const-list p. */
+{
+ if((t&NQ)==POINTER) t=UNSIGNED|LONG;
+ emit(f,"\t.%s\t",dct[t&NQ]);
+ if(!p->tree){
+ if(ISFLOAT(t)){
+ /* auch wieder nicht sehr schoen und IEEE noetig */
+ unsigned char *ip;
+ if(SHORT_DOUBLE){
+ eval_const(&p->val,t);
+ ip=(unsigned char *)&vfloat;
+ t=FLOAT;
+ }else
+ ip=(unsigned char *)&p->val.vdouble;
+ emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
+ if((t&NQ)!=FLOAT){
+ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
+ }
+ }else if((t&NQ)==LLONG){
+ zumax tmp;
+ eval_const(&p->val,t);
+ tmp=vumax;
+ vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff));
+ gval.vulong=zum2zul(vumax);
+ emitval(f,&gval,UNSIGNED|LONG);
+ emit(f,",");
+ vumax=zumand(tmp,ul2zum(0xffffffff));
+ gval.vulong=zum2zul(vumax);
+ emitval(f,&gval,UNSIGNED|LONG);
+ }else{
+ emitval(f,&p->val,t&NU);
+ }
+ }else{
+ no_suffix=1;
+ emit_obj(f,&p->tree->o,t&NU);
+ no_suffix=0;
+ }
+ emit(f,"\n");newobj=0;
+}
+
+
+/* The main code-generation routine. */
+/* f is the stream the code should be written to. */
+/* p is a pointer to a doubly linked list of ICs */
+/* containing the function body to generate code for. */
+/* v is a pointer to the function. */
+/* offset is the size of the stackframe the function */
+/* needs for local variables. */
+
+void gen_code(FILE *f,struct IC *p,struct Var *v,zmax offset)
+/* The main code-generation. */
+{
+ int c,t,i,lastcomp;
+ int q1wasreg,q2wasreg,zwasreg;
+ struct IC *m;
+ argsize=0;
+ if(DEBUG&1) printf("gen_code()\n");
+ for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
+ stackoffset=notpopped=dontpop=maxpushed=0;
+
+
+ /*FIXME*/
+ ret="\trts\n";
+
+ cc="";
+
+ for(m=p;m;m=m->next){
+ c=m->code;t=m->typf&NU;
+ if(c==ALLOCREG) {regs[m->q1.reg]=1;continue;}
+ if(c==FREEREG) {regs[m->q1.reg]=0;continue;}
+
+ if(notpopped&&!dontpop){
+ int flag=0;
+ if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+ emit(f,"\tadd\t%s,%ld\n",regnames[sp],notpopped);
+ pop(notpopped);notpopped=0;
+ }
+ }
+
+
+ /* convert MULT/DIV/MOD with powers of two */
+ if((t&NQ)<=LONG&&(m->q2.flags&(KONST|DREFOBJ))==KONST&&(t&NQ)<=LONG&&(c==MULT||((c==DIV||c==MOD)&&(t&UNSIGNED)))){
+ eval_const(&m->q2.val,t);
+ i=pof2(vmax);
+ if(i){
+ if(c==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ m->code=AND;
+ }else{
+ vmax=l2zm(i-1);
+ if(c==DIV) m->code=RSHIFT; else m->code=LSHIFT;
+ }
+ c=m->code;
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ if(c==AND){
+ insert_const(&m->q2.val,t);
+ }else{
+ insert_const(&m->q2.val,INT);
+ p->typf2=INT;
+ }
+ }
+ }
+ if(c==CALL&&argsize<zm2l(m->q2.val.vmax)) argsize=zm2l(m->q2.val.vmax);
+ }
+ peephole(p);
+
+ for(c=1;c<=MAXR;c++){
+ if(regsa[c]||regused[c]){
+ BSET(regs_modified,c);
+ }
+ }
+
+ localsize=(zm2l(offset)+3)/4*4;
+#if FIXED_SP
+ /*FIXME: adjust localsize to get an aligned stack-frame */
+#endif
+
+ function_top(f,v,localsize);
+
+ for(;p;p=p->next){
+ c=p->code;t=p->typf;
+ if(c==NOP) {p->z.flags=0;continue;}
+ if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
+ if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
+
+ if(DEBUG&256){emit(f,"# "); pric2(f,p);}
+ if(DEBUG&512) emit(f,"# stackoffset=%ld, notpopped=%ld, dontpop=%ld\n",stackoffset,notpopped,dontpop);
+ if(notpopped&&!dontpop){
+ int flag=0;
+ if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+ emit(f,"\tadd\t%s,%ld\n",regnames[sp],notpopped);
+ pop(notpopped);notpopped=0;
+ }
+ }
+
+ if(c==LABEL) {emit(f,"%s%d:\n",labprefix,t);continue;}
+ if(c==BRA){
+ if(0/*t==exit_label&&framesize==0*/)
+ emit(f,ret);
+ else
+ emit(f,"\tb\t%s%d\n",labprefix,t);
+ continue;
+ }
+ if(c>=BEQ&&c<BRA){
+ if(lastcomp&UNSIGNED)
+ emit(f,"\tb%s\t",ccu[c-BEQ]);
+ else
+ emit(f,"\tb%s\t",ccs[c-BEQ]);
+ if(isreg(q1)){
+ emit_obj(f,&p->q1,0);
+ emit(f,",");
+ }
+ emit(f,"%s%d\n",labprefix,t);
+ continue;
+ }
+ if(c==MOVETOREG){
+ load_reg(f,p->z.reg,&p->q1,regtype[p->z.reg]->flags);
+ continue;
+ }
+ if(c==MOVEFROMREG){
+ store_reg(f,p->q1.reg,&p->z,regtype[p->q1.reg]->flags);
+ continue;
+ }
+ if(c==PUSH)
+ dontpop+=zm2l(p->q2.val.vmax);
+ if((c==ASSIGN||c==PUSH)&&((t&NQ)>POINTER||((t&NQ)==CHAR&&zm2l(p->q2.val.vmax)!=1))){
+ int i,cnt,unit,lab,treg,acnt=0,atreg=0;
+ long size;
+ char *ut;
+ if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&®_is_scratched(p,p->q1.reg)){
+ q1reg=p->q1.reg;
+ if(p->q1.am) ierror(0);
+ }else{
+ q1reg=t1;
+ if(p->q1.flags&(REG|DREFOBJ)){
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,q1reg,&p->q1,POINTER);
+ }else
+ load_address(f,q1reg,&p->q1,POINTER);
+ }
+ if((p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&®_is_scratched(p,p->z.reg)){
+ zreg=p->z.reg;
+ if(p->z.am) ierror(0);
+ }else if(c==PUSH){
+ zreg=sp;
+ }else{
+ if(q1reg==t1)
+ zreg=t2;
+ else
+ zreg=t1;
+ if(p->z.flags&(REG|DREFOBJ)){
+ p->z.flags&=~DREFOBJ;
+ load_reg(f,zreg,&p->z,POINTER);
+ }else
+ load_address(f,zreg,&p->z,POINTER);
+ }
+ if(zreg==t2){
+ treg=get_reg(f,p);
+ atreg=1;
+ }else if(zreg==t1||q1reg==t1)
+ treg=t2;
+ else
+ treg=t1;
+
+ unit=1;ut="b";
+ size=zm2l(p->q2.val.vmax);
+
+ if(c==PUSH)
+ emit(f,"\tadd\t%s,%ld\n",regnames[q1reg],size);
+
+ if(size/unit>=8){
+ if(treg!=t2&&zreg!=t2)
+ cnt=t2;
+ else{
+ cnt=get_reg(f,p);
+ acnt=1;
+ }
+ emit(f,"\tmov\t%s,%ld\n",regnames[cnt],(size/unit)>>2);
+ emit(f,"%s%d:\n",labprefix,++label);
+ }
+
+ for(i=0;i<((size/unit>4)?4:size/unit);i++){
+ if(c!=PUSH){
+ emit(f,"\tld%s\t%s,(%s)++\n",ut,regnames[treg],regnames[q1reg]);
+ emit(f,"\tst%s\t%s,(%s)++\n",ut,regnames[treg],regnames[zreg]);
+ }else{
+ emit(f,"\tld%s\t%s,--(%s)\n",ut,regnames[treg],regnames[q1reg]);
+ emit(f,"\tst%s\t%s,--(%s)\n",ut,regnames[treg],regnames[zreg]);
+ }
+ }
+ if(size/unit>=8){
+ emit(f,"\taddcmpbne\t%s,-1,0,%s%d\n",regnames[cnt],labprefix,label);
+ }
+ for(i=0;i<((size/unit)&3);i++){
+ if(c!=PUSH){
+ emit(f,"\tld%s\t%s,(%s)++\n",ut,regnames[treg],regnames[q1reg]);
+ emit(f,"\tst%s\t%s,(%s)++\n",ut,regnames[treg],regnames[zreg]);
+ }else{
+ emit(f,"\tld%s\t%s,--(%s)\n",ut,regnames[treg],regnames[q1reg]);
+ emit(f,"\tst%s\t%s,--(%s)\n",ut,regnames[treg],regnames[zreg]);
+ }
+ }
+ if(c==PUSH)
+ push(size);
+ if(acnt) free_reg(f,cnt);
+ if(atreg) free_reg(f,treg);
+ continue;
+ }
+
+ if(c==CALL){
+ int reg;
+ /*FIXME*/
+#if 0
+ if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)){
+ if(framesize+zum2ul(p->q1.v->fi->stack1)>stack)
+ stack=framesize+zum2ul(p->q1.v->fi->stack1);
+ }else
+ stack_valid=0;
+#endif
+ /*FIXME: does not work with fixed parameters on stack */
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
+ emit(f,"\tadd\t%s,%s,%ld\n",regnames[r0],regnames[sp],localsize+rsavesize-stackoffset);
+ continue;
+ }
+
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
+ emit_inline_asm(f,p->q1.v->fi->inline_asm);
+ }else{
+ if((p->q1.flags&(REG|DREFOBJ))==DREFOBJ){
+ p->q1.flags&=~DREFOBJ;
+ load_reg(f,t1,&p->q1,POINTER);
+ p->q1.flags|=(DREFOBJ|REG);
+ p->q1.reg=t1;
+ }
+ emit(f,"\tbl\t");
+ if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
+ emit(f,"%s",regnames[p->q1.reg]);
+ }else{
+ no_suffix=1;
+ emit_obj(f,&p->q1,t);
+ no_suffix=0;
+ }
+ emit(f,"\n");
+ }
+
+ if(!zmeqto(p->q2.val.vmax,l2zm(0L))){
+ notpopped+=zm2l(p->q2.val.vmax);
+ dontpop-=zm2l(p->q2.val.vmax);
+ if(!NODELAYEDPOP&&!vlas&&stackoffset==-notpopped){
+ /* Entfernen der Parameter verzoegern */
+ }else{
+ emit(f,"\tadd\t%s,%ld\n",regnames[sp],zm2l(p->q2.val.vmax));
+ pop(zm2l(p->q2.val.vmax));
+ notpopped-=zm2l(p->q2.val.vmax);
+ }
+ }
+
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+ bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
+ }else{
+ int i;
+ for(i=1;i<=MAXR;i++){
+ if(regscratch[i]) BSET(regs_modified,i);
+ }
+ }
+ continue;
+ }
+
+ if(c==ADDRESS){
+ if(isreg(z))
+ zreg=p->z.reg;
+ else
+ zreg=t1;
+ load_address(f,zreg,&p->q1,POINTER);
+ save_result(f,p);
+ continue;
+ }
+
+ if(isreg(q1)) q1wasreg=1; else q1wasreg=0;
+ if(isreg(q2)) q2wasreg=1; else q2wasreg=0;
+ if(isreg(z)) zwasreg=1; else zwasreg=0;
+
+ p=preload(f,p);
+ c=p->code;
+ if(c==SUBPFP) c=SUB;
+ if(c==ADDI2P) c=ADD;
+ if(c==SUBIFP) c=SUB;
+ if(c==CONVERT){
+ if(ISFLOAT(q1typ(p))){
+ if(ztyp(p)&UNSIGNED) ierror(0);
+ if(ISFLOAT(ztyp(p)))
+ emit(f,"\tmov%s\t%s,%s\n",cc,regnames[zreg],regnames[q1reg]);
+ else
+ emit(f,"\tftrunc%s\t%s,%s\n",cc,regnames[zreg],regnames[q1reg]);
+ save_result(f,p);
+ continue;
+ }
+ if(ISFLOAT(ztyp(p))){
+ emit(f,"\tflt%c%s\t%s,%s\n",(q1typ(p)&UNSIGNED)?'u':'s',cc,regnames[zreg],regnames[q1reg]);
+ save_result(f,p);
+ continue;
+ }
+ if(sizetab[q1typ(p)&NQ]<sizetab[ztyp(p)&NQ]){
+ int mask;
+ if((q1typ(p)&NQ)==CHAR)
+ mask=7;
+ else
+ mask=15;
+ if(q1typ(p)&UNSIGNED)
+ mask++;
+ if(q1wasreg||(q1typ(p)&NU)==CHAR)
+ emit(f,"\text%c%s\t%s,%s,%d\n",(q1typ(p)&UNSIGNED)?'u':'s',cc,regnames[zreg],regnames[q1reg],mask);
+ }else{
+ zreg=q1reg;
+ }
+ save_result(f,p);
+ continue;
+ }
+ if(c==KOMPLEMENT){
+ emit(f,"\tmvn%s\t%s,%s\n",cc,regnames[zreg],regnames[q1reg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c==SETRETURN){
+ if(isreg(q1)){
+ if(p->q1.reg!=p->z.reg)
+ emit(f,"\tmov%s\t%s,%s\n",cc,regnames[p->z.reg],regnames[p->q1.reg]);
+ }else
+ load_reg(f,p->z.reg,&p->q1,t);
+ BSET(regs_modified,p->z.reg);
+ continue;
+ }
+ if(c==GETRETURN){
+ if(p->q1.reg){
+ zreg=p->q1.reg;
+ save_result(f,p);
+ }else
+ p->z.flags=0;
+ continue;
+ }
+
+ if(c==ASSIGN||c==PUSH){
+ if(t==0) ierror(0);
+ if(c==PUSH){
+ if(!q1reg){
+ q1reg=t1;
+ load_reg(f,q1reg,&p->q1,t);
+ }
+ if(SHORT_DOUBLE&&ISFLOAT(t)) t=FLOAT;
+ emit(f,"\tst%s%s\t%s,--(%s)\n",sdt(t),cc,regnames[q1reg],regnames[sp]);
+ push(zm2l(p->q2.val.vmax));
+ continue;
+ }
+ if(c==ASSIGN){
+ if(isreg(q1)){
+ if(isreg(z))
+ emit(f,"\tmov%s\t%s,%s\n",cc,regnames[zreg],regnames[p->q1.reg]);
+ else
+ zreg=p->q1.reg;
+ }else
+ load_reg(f,zreg,&p->q1,t);
+ save_result(f,p);
+ }
+ continue;
+ }
+ if(c==MINUS){
+ load_reg(f,zreg,&p->q1,t);
+ emit(f,"\tneg%s\t%s,%s\n",cc,regnames[zreg],regnames[zreg]);
+ save_result(f,p);
+ continue;
+ }
+ if(c==TEST){
+ emit(f,"\tcmp%s\t",cc);
+ emit_obj(f,&p->q1,t);
+ emit(f,",0\n");
+ lastcomp=t;
+ continue;
+ }
+ if(c==COMPARE){
+ if(ISFLOAT(t))
+ emit(f,"\tfcmp%s\t%s,",cc,regnames[t1]);
+ else
+ emit(f,"\tcmp%s\t",cc);
+ emit_obj(f,&p->q1,t);
+ emit(f,",");
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ lastcomp=t;
+ continue;
+ }
+ if(c==MOD){
+ /* TODO: is there a faster way? */
+ int m;
+ if(q2reg!=t2)
+ m=t2;
+ else
+ m=get_reg(f,p);
+ if(!isreg(q1)||p->q1.reg!=zreg)
+ load_reg(f,zreg,&p->q1,t);
+ emit(f,"\tdiv%c%s\t%s,%s,",(t&UNSIGNED)?'u':'s',cc,regnames[m],regnames[zreg]);
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ emit(f,"\tmul%s\t%s,",cc,regnames[m]);
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ emit(f,"\tsub%s\t%s,%s,%s\n",cc,regnames[zreg],regnames[zreg],regnames[m]);
+ free_reg(f,m);
+ save_result(f,p);
+ continue;
+ }
+ if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<MOD)){
+ if(c>=OR&&c<=AND)
+ emit(f,"\t%s%s\t%s,",logicals[c-OR],cc,regnames[zreg]);
+ else{
+ if(ISFLOAT(t))
+ emit(f,"\t%s%s\t%s,",farithmetics[c-LSHIFT],cc,regnames[zreg]);
+ else
+ emit(f,"\t%s%s\t%s,",(t&UNSIGNED)?uarithmetics[c-LSHIFT]:arithmetics[c-LSHIFT],cc,regnames[zreg]);
+ }
+ if(!isreg(q1)||p->q1.reg!=zreg||*cc||c==DIV||ISFLOAT(t)){
+ emit_obj(f,&p->q1,t);
+ emit(f,",");
+ }
+ emit_obj(f,&p->q2,t);
+ emit(f,"\n");
+ save_result(f,p);
+ continue;
+ }
+ pric2(stdout,p);
+ ierror(0);
+ }
+
+ if(notpopped){
+ emit(f,"\tadd\t%s,%ld\n",regnames[sp],notpopped);
+ pop(notpopped);notpopped=0;
+ }
+
+ function_bottom(f,v,localsize);
+ if(stack_valid){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_STACK;
+ v->fi->stack1=stack;
+ }
+ /*emit(f,"# stacksize=%lu%s\n",zum2ul(stack),stack_valid?"":"+??");*/
+}
+
+int shortcut(int code,int typ)
+{
+ return 0;
+}
+
+int reg_parm(struct reg_handle *m, struct Typ *t,int vararg,struct Typ *d)
+{
+ int f;
+
+ if(vararg)
+ return 0;
+
+ f=t->flags&NQ;
+ if(ISINT(f)||ISFLOAT(f)||f==POINTER){
+ if(zmeqto(sizetab[f],l2zm(8L))){
+ if(m->gregs<=r4){
+ m->gregs=(m->gregs+1)&0xfe;
+ m->gregs+=2;
+ if(m->gregs==r1)
+ return r0r1;
+ else if(m->gregs==r3)
+ return r2r3;
+ else if(m->gregs==r5)
+ return r4r5;
+ else
+ ierror(0);
+ }else
+ return 0;
+ }else{
+ if(m->gregs<=r4)
+ return ++m->gregs;
+ else
+ return 0;
+ }
+ }
+ return 0;
+}
+
+int handle_pragma(const char *s)
+{
+}
+void cleanup_cg(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+ if(f) section=-1;
+}
+
+char *use_libcall(int c,int t,int t2)
+/* Return name of library function, if this node should be
+ implemented via libcall. */
+{
+ static char fname[16];
+ char *ret = NULL;
+
+ if(c==COMPARE){
+ if((t&NQ)==DOUBLE) t=(SHORT_DOUBLE)?FLOAT:LDOUBLE;
+ if((t&NQ)==LLONG||t==LDOUBLE){
+ sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }else{
+ t&=NU;
+ t2&=NU;
+ if(SHORT_DOUBLE){
+ if(ISFLOAT(t)) t=FLOAT;
+ if(ISFLOAT(t2)) t2=FLOAT;
+ }else{
+ if(t==DOUBLE) t=LDOUBLE;
+ if(t2==DOUBLE) t2=LDOUBLE;
+ }
+ if(c==CONVERT){
+ if(t==t2) return 0;
+ if(t==FLOAT&&t2==LDOUBLE) return "__flt64toflt32";
+ if(t==LDOUBLE&&t2==FLOAT) return "__flt32toflt64";
+ if(t!=LDOUBLE&&t2!=LDOUBLE&&(t&NQ)!=LLONG&&(t2&NQ)!=LLONG) return 0;
+ if(ISFLOAT(t)){
+ sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64);
+ ret=fname;
+ }
+ if(ISFLOAT(t2)&&(t&NU)==LLONG){
+ sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+ if((t&NQ)==LLONG||t==DOUBLE){
+ if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
+ if(t==(UNSIGNED|LLONG)&&(c==DIV||c==MOD||c==RSHIFT)){
+ sprintf(fname,"__%suint64",ename[c]);
+ ret=fname;
+ }else if((t&NQ)==LLONG){
+ sprintf(fname,"__%sint64",ename[c]);
+ ret=fname;
+ }else{
+ sprintf(fname,"__%s%s%s%ld",ename[c],(t&UNSIGNED)?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
+ ret=fname;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
diff --git a/machines/vidcore/machine.dt b/machines/vidcore/machine.dt
new file mode 100644
index 0000000..526c8d4
--- /dev/null
+++ b/machines/vidcore/machine.dt
@@ -0,0 +1,16 @@
+S8BS
+S8BU
+S16BSBE S16BSLE
+S16BUBE S16BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S32BSBE S32BSLE
+S32BUBE S32BULE
+S64BSBE S64BSLE
+S64BUBE S64BULE
+S32BIEEEBE
+S64BIEEEBE
+S64BIEEEBE
+S32BUBE S32BULE
+
+
diff --git a/machines/vidcore/machine.h b/machines/vidcore/machine.h
new file mode 100644
index 0000000..408e581
--- /dev/null
+++ b/machines/vidcore/machine.h
@@ -0,0 +1,131 @@
+/* Backend for VideoCore IV
+ (c) in 2013 by Volker Barthelmann
+*/
+
+/* buil-time configurable options: */
+#define NUM_GPRS 48
+
+#include "dt.h"
+
+
+/* This struct can be used to implement machine-specific */
+/* addressing-modes. */
+/* Currently possible are (const,gpr) and (gpr,gpr) */
+struct AddressingMode{
+ int flags;
+ int base;
+ long offset;
+};
+
+/* The number of registers of the target machine. */
+#define MAXR 48
+
+/* Number of commandline-options the code-generator accepts. */
+#define MAXGF 20
+
+/* If this is set to zero vbcc will not generate ICs where the */
+/* target operand is the same as the 2nd source operand. */
+/* This can sometimes simplify the code-generator, but usually */
+/* the code is better if the code-generator allows it. */
+#define USEQ2ASZ 0
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MINADDI2P INT
+
+/* This specifies the smallest integer type that can be added to a */
+/* pointer. */
+#define MAXADDI2P INT
+
+/* If the bytes of an integer are ordered most significant byte */
+/* byte first and then decreasing set BIGENDIAN to 1. */
+#define BIGENDIAN 0
+
+/* If the bytes of an integer are ordered lest significant byte */
+/* byte first and then increasing set LITTLEENDIAN to 1. */
+#define LITTLEENDIAN 1
+
+/* Note that BIGENDIAN and LITTLEENDIAN are mutually exclusive. */
+
+/* If switch-statements should be generated as a sequence of */
+/* SUB,TST,BEQ ICs rather than COMPARE,BEQ ICs set this to 1. */
+/* This can yield better code on some machines. */
+#define SWITCHSUBS 1
+
+/* In optimizing compilation certain library memcpy/strcpy-calls */
+/* with length known at compile-time will be inlined using an */
+/* ASSIGN-IC if the size is less or equal to INLINEMEMCPY. */
+/* The type used for the ASSIGN-IC will be UNSIGNED|CHAR. */
+#define INLINEMEMCPY 1024
+
+/* Parameters are sometimes passed in registers without __reg. */
+#define HAVE_REGPARMS 1
+
+/* Parameters on the stack should be pushed in order rather than */
+/* in reverse order. */
+#undef ORDERED_PUSH
+
+/* Structure for reg_parm(). */
+struct reg_handle{
+ unsigned long gregs;
+};
+
+/* We have some target-specific variable attributes. */
+#define HAVE_TARGET_ATTRIBUTES
+
+/* We have target-specific pragmas */
+#define HAVE_TARGET_PRAGMAS
+
+/* We keep track of all registers modified by a function. */
+#define HAVE_REGS_MODIFIED 1
+
+/* We have a implement our own cost-functions to adapt
+ register-allocation */
+#define HAVE_TARGET_RALLOC 1
+#define cost_move_reg(x,y) 1
+#define cost_load_reg(x,y) 2
+#define cost_save_reg(x,y) 2
+#define cost_pushpop_reg(x) 3
+
+/* size of buffer for asm-output, this can be used to do
+ peephole-optimizations of the generated assembly-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4
+
+/* We have no asm_peephole to optimize assembly-output */
+#define HAVE_TARGET_PEEPHOLE 0
+
+/* we do not have a mark_eff_ics function, this is used to prevent
+ optimizations on code which can already be implemented by efficient
+ assembly */
+#undef HAVE_TARGET_EFF_IC
+
+/* we only need the standard data types (no bit-types, different pointers
+ etc.) */
+#undef HAVE_EXT_TYPES
+#undef HAVE_TGT_PRINTVAL
+
+/* we do not need extra elements in the IC */
+#undef HAVE_EXT_IC
+
+/* we do use unsigned int as size_t (but unsigned long, the default) */
+#define HAVE_INT_SIZET 1
+
+/* we need register-pairs */
+#define HAVE_REGPAIRS 1
+
+
+/* do not create CONVERT ICs from integers smaller than int to floats */
+#define MIN_INT_TO_FLOAT_TYPE INT
+
+/* do not create CONVERT ICs from floats to ints smaller than int */
+#define MIN_FLOAT_TO_INT_TYPE INT
+
+/* do not create CONVERT_ICs from floats to unsigned integers */
+#define AVOID_FLOAT_TO_UNSIGNED 1
+
+/* do not create CONVERT_ICs from unsigned integers to floats */
+#define AVOID_UNSIGNED_TO_FLOAT 0
+
+#define HAVE_LIBCALLS 1
diff --git a/machines/z/machine.c b/machines/z/machine.c
new file mode 100755
index 0000000..a242fff
--- /dev/null
+++ b/machines/z/machine.c
@@ -0,0 +1,2719 @@
+/* z/machine.c
+ * Code generator for the Z-machine.
+ * (C) David Given 2001
+ * conversion to vbcc 0.8 by Volker Barthelmann
+ */
+
+/* This code is licensed under the MIT open source license.
+ *
+ * Copyright (c) 2001, David Given
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/* This code generator produces code for the Z-machine. The Z-machine is the
+ * highly peculiar virtual machine used for the old Infocom text adventures;
+ * these days, an extended form is still used in the interactive fiction genre
+ * of games. Usually, a dedicated compiler called Inform is used to generate
+ * code, but it would be nice to be able to use real C, so here we are.
+ *
+ * The Z-machine is (mostly) a semi-stack-based Harvard architecture machine.
+ * (Split code and data space, although they can share if you're clever. And
+ * mad.) It has no registers, but it does have procedure local variables which
+ * will do instead. It has a dedicated stack but as it's not accessible by
+ * ordinary memory it's not useful for C. It uses 8 and 16 bit words, so we'll
+ * have to emulate 32-bit arithmetic.
+ *
+ * For more information, including code for Inform, various interpreters, more
+ * documentation than you can shake a stick at, and the full technical reference
+ * for the Z-machine, check out the Interactive Fiction archive, at
+ * http://www.ifarchive.org.
+ *
+ * Things to note: there is no Z-machine assembler. (Well, there's zasm, but it's
+ * really just a rumour.) Luckily, Inform has an assembler mode, where it'll
+ * generate raw Z-machine opcodes. Unluckily, it's horribly buggy... So we're
+ * going to have to generate Inform source, which seems at first to be rather
+ * silly, but as Inform is quite a simple compiler we can make sure that it's
+ * only going to generate the instructions we want it to generate.
+ */
+
+/* vbcc-mandated header. */
+
+#include "supp.h"
+static char FILE_[]=__FILE__;
+char cg_copyright[]="vbcc code-generator for Z-machine V0.0a (c) in 2001 by David Given";
+
+/* Command-line flags. */
+
+int g_flags[MAXGF] = {
+ STRINGFLAG,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+};
+char *g_flags_name[MAXGF] = {
+ "module-name",
+ "trace-calls",
+ "trace-all",
+ "safe-branches",
+ "comment-ic",
+ "comment-misc"
+};
+union ppi g_flags_val[MAXGF];
+
+/* Type alignment. Much better code is generated if we can use even alignment.
+ */
+
+zmax align[MAX_TYPE+1] = {
+ 0, /* 0: unused */
+ 1, /* 1: CHAR */
+ 2, /* 2: SHORT */
+ 2, /* 3: INT */
+ 2, /* 4: LONG */
+ 2, /* 5: LLONG */
+ 2, /* 6: FLOAT */
+ 2, /* 7: DOUBLE */
+ 2, /* 8: LDOUBLE */
+ 2, /* 9: VOID */
+ 2, /* 10: POINTER */
+ 1, /* 11: ARRAY */
+ 1, /* 12: STRUCT */
+ 1, /* 13: UNION */
+ 1, /* 14: ENUM */
+ 1, /* 15: FUNKT */
+};
+
+/* Alignment that is valid for all types. */
+
+zmax maxalign = 2;
+
+/* Number of bits in a char. */
+
+zmax char_bit = 8;
+
+/* Sizes of all elementary types, in bytes. */
+
+zmax sizetab[MAX_TYPE+1] = {
+ 0, /* 0: unused */
+ 1, /* 1: CHAR */
+ 2, /* 2: SHORT */
+ 2, /* 3: INT */
+ 4, /* 4: LONG */
+ 8, /* 5: LLONG */
+ 4, /* 6: FLOAT */
+ 8, /* 7: DOUBLE */
+ 8, /* 8: LDOUBLE */
+ 0, /* 9: VOID */
+ 2, /* 10: POINTER */
+ 0, /* 11: ARRAY */
+ 0, /* 12: STRUCT */
+ 0, /* 13: UNION */
+ 2, /* 14: ENUM */
+ 0, /* 15: FUNKT */
+};
+
+/* Minimum and Maximum values each type can have. */
+/* Must be initialized in init_cg(). */
+zmax t_min[MAX_TYPE+1];
+zumax t_max[MAX_TYPE+1];
+zumax tu_max[MAX_TYPE+1];
+
+/* Names of all the registers.
+ * We can have 16 local variables per routine. Var 0 is always the C stack
+ * pointer, xp. All the others can be used by the compiler. xp doesn't actually
+ * appear in the register map, so we get 15 main registers.
+ */
+
+char* regnames[] = {
+ "sp", /* vbcc doesn't use this, but we do */
+ "xp", "r0", "r1", "r2", "r3", "r4", "r5", "r6",
+ "r7", "r8", "r9", "r10", "r11", "r12"};
+#define XP 1
+#define USERREG 2
+
+/* The size of each register, in byes. */
+
+zmax regsize[] = {
+ 0,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2};
+
+/* Type needed to store each register. */
+
+struct Typ ityp = {INT};
+struct Typ* regtype[] = {
+ NULL,
+ &ityp, &ityp, &ityp, &ityp, &ityp, &ityp, &ityp, &ityp,
+ &ityp, &ityp, &ityp, &ityp, &ityp, &ityp};
+
+/* These registers are those dedicated for use by the backend. These ones will
+ * not be used by the code generator. */
+
+int regsa[] = {
+ 0,
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0};
+
+/* Specifies which registers may be destroyed by function calls. As we're
+ * storing our registers in local variables so they're being automatically
+ * saved for us, none of them.
+ */
+
+int regscratch[] = {
+ 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0};
+
+/* Default state for register parameter passing. */
+
+struct reg_handle empty_reg_handle =
+ {USERREG};
+
+/* Prefix for labels. */
+
+static char* labelprefix = "L";
+
+/* Name of the current module; used for generating unique names for statics and
+ * the constant pool. */
+
+static char* modulename;
+
+/* Stack frame layout:
+ *
+ * --------------
+ * Arg 4 (Arguments being passed to this function)
+ * Arg 3
+ * Arg 2
+ * Arg 1
+ * -------------- xp + stackparamadjust + stackoffset
+ * Local 4 (This function's temp space)
+ * Local 3
+ * Local 2
+ * Local 1
+ * -------------- xp + stackparamadjust
+ * Arg 2 (Arguments this function has pushed to pass
+ * Arg 1 to a called function)
+ * -------------- xp
+ *
+ * Any area may be zero in size. (Although stackoffset is always at least 2 for
+ * some inadequately explained reason.)
+ */
+
+static int stackoffset;
+static int stackparamadjust;
+
+/* Represents something the Z-machine can use as an instruction operand. */
+
+struct zop {
+ int type;
+ union {
+ int reg;
+ zmax constant;
+ char* identifier;
+ } val;
+};
+
+enum {
+ ZOP_STACK,
+ ZOP_REG,
+ ZOP_CONSTANT,
+ ZOP_EXTERN,
+ ZOP_STATIC,
+ ZOP_CONSTANTADDR
+};
+
+/* Some useful zops. */
+
+struct zop zop_zero = {ZOP_CONSTANT, {constant: 0}};
+struct zop zop_xp = {ZOP_REG, {reg: XP}};
+struct zop zop_stack = {ZOP_STACK, 0};
+
+/* Temporaries used to store comparison register numbers. */
+
+static struct zop compare1;
+static struct zop compare2;
+
+/* Keeps track of whether we've emitted anything or not. Used to determine
+ * whether to emit the seperating ; or not. If it's 1, we haven't emitted
+ * anything. If it's -1, we're doing an array, so we need to emit a final (0)
+ * to finish it off if it's only one byte long. 0 for anything else. */
+
+static int virgin = 1;
+
+/* The current variable we're emitting data for. */
+
+struct variable {
+ int type;
+ union {
+ char* identifier;
+ int number;
+ } val;
+ zint offset;
+};
+
+struct variable currentvar;
+
+/* Inform can't emit variable references inside arrays. So when vbcc wants to
+ * put, say, the address of something in a global variable, we have to write it
+ * in later. A linked list of these structures keeps track of the items that
+ * need fixing up. */
+
+struct fixup {
+ struct fixup* next;
+ struct variable identifier;
+ struct variable value;
+ zmax offset;
+};
+
+static struct fixup* fixuplist = NULL;
+
+/* 32-bit values are stored in a constant pool, for simplicity. It's kept track
+ * of in this linked list. */
+
+struct constant {
+ struct constant* next;
+ int id;
+ zmax value;
+};
+
+static struct constant* constantlist = NULL;
+static int constantnum = 0;
+
+/* The function we're currently compiling. */
+
+static struct Var* function;
+
+/* Function prototypes. */
+
+static void emit_add(FILE* fp, struct zop* q1, struct zop* q2, struct zop* z);
+static void read_reg(FILE* fp, struct obj* obj, int typf, int reg);
+static int addconstant(zmax value);
+
+/* Emit debugging info. */
+
+static void debugemit(FILE* fp, char* fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (g_flags[5] & USEDFLAG)
+ vfprintf(fp, fmt, ap);
+ va_end(ap);
+}
+
+/* Do we need to emit a ; before the next thing? */
+
+static void reflower(FILE* fp)
+{
+ if (!virgin)
+ fprintf(fp, ";\n");
+ if (virgin == -1)
+ {
+ if (currentvar.offset == 1)
+ fprintf(fp, "(0)");
+ fprintf(fp, ";");
+ }
+ virgin = 0;
+}
+
+/* Extract the sign extended byte n of a value. */
+
+static char xbyte(zmax val, int byte)
+{
+ val <<= (sizeof(val)*8) - (byte*8) - 8;
+ val >>= (sizeof(val)*8) - 8;
+ return (unsigned char) val;
+}
+
+/* Extract the sign extended word n of a value. */
+
+static zshort xword(zmax val, int word)
+{
+ val <<= (sizeof(val)*8) - (word*16) - 16;
+ val >>= (sizeof(val)*8) - 16;
+ return (zshort) val;
+}
+
+/* Debug function: prints the text name of a type. */
+
+static void dump_type(FILE* fp, int typf)
+{
+ switch (typf)
+ {
+ case VOID: fprintf(fp, "VOID"); break;
+ case CHAR: fprintf(fp, "CHAR"); break;
+ case SHORT: fprintf(fp, "SHORT"); break;
+ case INT: fprintf(fp, "INT"); break;
+ case LONG: fprintf(fp, "LONG"); break;
+ case POINTER: fprintf(fp, "POINTER"); break;
+ case STRUCT: fprintf(fp, "STRUCT"); break;
+ case ARRAY: fprintf(fp, "ARRAY"); break;
+ case UNION: fprintf(fp, "UNION"); break;
+ case FUNKT: fprintf(fp, "FUNKT"); break;
+ default: fprintf(fp, "unknown %X", typf);
+ }
+}
+
+/* Debug function: outputs the obj. */
+
+static void dump_obj(FILE* fp, struct obj* obj, int typf)
+{
+ int f = obj->flags & (KONST|REG|VAR|DREFOBJ|VARADR);
+
+ if (f == 0)
+ {
+ fprintf(fp, "[]");
+ return;
+ }
+
+ if (f & DREFOBJ)
+ fprintf(fp, "*");
+
+ if (f & VARADR)
+ fprintf(fp, "&");
+
+ if (f == KONST)
+ {
+ switch (typf & NU)
+ {
+ case CHAR:
+ fprintf(fp, "[char #%d]", obj->val.vchar);
+ break;
+
+ case UNSIGNED|CHAR:
+ fprintf(fp, "[uchar #%u]", obj->val.vuchar);
+ break;
+
+ case SHORT:
+ fprintf(fp, "[short #%d]", obj->val.vshort);
+ break;
+
+ case UNSIGNED|SHORT:
+ fprintf(fp, "[ushort #%u]", obj->val.vushort);
+ break;
+
+ case INT:
+ fprintf(fp, "[int #%d]", obj->val.vint);
+ break;
+
+ case UNSIGNED|INT:
+ fprintf(fp, "[uint #%d]", obj->val.vuint);
+ break;
+
+ case LONG:
+ fprintf(fp, "[long #%d]", obj->val.vlong);
+ break;
+
+ case UNSIGNED|LONG:
+ fprintf(fp, "[ulong #%u]", obj->val.vulong);
+ break;
+
+ case FLOAT:
+ fprintf(fp, "[float #%04X]", obj->val.vfloat);
+ break;
+
+ case DOUBLE:
+ fprintf(fp, "[double #%08X]", obj->val.vdouble);
+ break;
+#if 0
+ case POINTER:
+ fprintf(fp, "[pointer #%04X]", obj->val.vpointer);
+ break;
+#endif
+ }
+ }
+ else if (f == REG)
+ fprintf(fp, "[reg %s]", regnames[obj->reg]);
+ else if (f == (REG|DREFOBJ))
+ fprintf(fp, "[deref reg %s]", regnames[obj->reg]);
+ //else if (f & VAR)
+ else
+ {
+ fprintf(fp, "[var ");
+ dump_type(fp, typf);
+ fprintf(fp, " %s", obj->v->identifier);
+
+ if ((obj->v->storage_class == AUTO) ||
+ (obj->v->storage_class == REGISTER))
+ {
+ zmax offset = obj->v->offset;
+ //if (offset < 0)
+ // offset = -(offset+maxalign);
+ fprintf(fp, " at fp%+d", offset);
+ }
+
+ fprintf(fp, "+%ld", obj->val.vlong);
+
+ if (f & REG)
+ fprintf(fp, " in %s", regnames[obj->reg]);
+ fprintf(fp, "]");
+ }
+}
+
+/* Debug function: outputs the ic, as a comment. */
+
+static void dump_ic(FILE* fp, struct IC* ic)
+{
+ char* p;
+
+ if (!ic)
+ return;
+
+ if (!(g_flags[4] & USEDFLAG))
+ return;
+
+ if (g_flags[2] & USEDFLAG)
+ fprintf(fp, "print \"");
+ else
+ fprintf(fp, "! ");
+
+ switch (ic->code)
+ {
+ case ASSIGN: p = "ASSIGN"; break;
+ case OR: p = "OR"; break;
+ case XOR: p = "XOR"; break;
+ case AND: p = "AND"; break;
+ case LSHIFT: p = "LSHIFT"; break;
+ case RSHIFT: p = "RSHIFT"; break;
+ case ADD: p = "ADD"; break;
+ case SUB: p = "SUB"; break;
+ case MULT: p = "MULT"; break;
+ case DIV: p = "DIV"; break;
+ case MOD: p = "MOD"; break;
+ case KOMPLEMENT: p = "KOMPLEMENT"; break;
+ case MINUS: p = "MINUS"; break;
+ case ADDRESS: p = "ADDRESS"; break;
+ case CALL: p = "CALL"; break;
+#if 0
+ case CONVCHAR: p = "CONVCHAR"; break;
+ case CONVSHORT: p = "CONVSHORT"; break;
+ case CONVINT: p = "CONVINT"; break;
+ case CONVLONG: p = "CONVLONG"; break;
+ case CONVFLOAT: p = "CONVFLOAT"; break;
+ case CONVDOUBLE: p = "CONVDOUBLE"; break;
+ case CONVPOINTER: p = "CONVPOINTER"; break;
+ case CONVUCHAR: p = "CONVUCHAR"; break;
+ case CONVUSHORT: p = "CONVUSHORT"; break;
+ case CONVUINT: p = "CONVUINT"; break;
+ case CONVULONG: p = "CONVULONG"; break;
+#endif
+ case ALLOCREG: p = "ALLOCREG"; break;
+ case FREEREG: p = "FREEREG"; break;
+ case COMPARE: p = "COMPARE"; break;
+ case TEST: p = "TEST"; break;
+ case LABEL: p = "LABEL"; break;
+ case BEQ: p = "BEQ"; break;
+ case BNE: p = "BNE"; break;
+ case BLT: p = "BLT"; break;
+ case BGT: p = "BGT"; break;
+ case BLE: p = "BLE"; break;
+ case BGE: p = "BGE"; break;
+ case BRA: p = "BRA"; break;
+ case PUSH: p = "PUSH"; break;
+ case ADDI2P: p = "ADDI2P"; break;
+ case SUBIFP: p = "SUBIFP"; break;
+ case SUBPFP: p = "SUBPFP"; break;
+ case GETRETURN: p = "GETRETURN"; break;
+ case SETRETURN: p = "SETRETURN"; break;
+ case MOVEFROMREG: p = "MOVEFROMREG"; break;
+ case MOVETOREG: p = "MOVETOREG"; break;
+ case NOP: p = "NOP"; break;
+ default: p = "???";
+ }
+
+ fprintf(fp, "%s ", p);
+ dump_type(fp, ic->typf);
+ fprintf(fp, " ");
+
+ switch (ic->code)
+ {
+ case LABEL:
+ case BEQ:
+ case BNE:
+ case BLT:
+ case BGT:
+ case BLE:
+ case BGE:
+ case BRA:
+ fprintf(fp, "%d", ic->typf);
+ goto epilogue;
+ }
+
+ dump_obj(fp, &ic->q1, ic->typf);
+ fprintf(fp, " ");
+ dump_obj(fp, &ic->q2, ic->typf);
+ fprintf(fp, " -> ");
+ dump_obj(fp, &ic->z, ic->typf);
+
+epilogue:
+ if (g_flags[2] & USEDFLAG)
+ fprintf(fp, "^\";\n");
+ else
+ fprintf(fp, "\n");
+}
+
+/* Initialise the code generator. This is called once. Returns 0 if things go
+ * wrong. */
+
+int init_cg(void)
+{
+ modulename = g_flags_val[0].p;
+ if (!modulename)
+ modulename = "";
+
+ /* Initialize the min/max-settings. Note that the types of the */
+ /* host system may be different from the target system and you may */
+ /* only use the smallest maximum values ANSI guarantees if you */
+ /* want to be portable. */
+ /* That's the reason for the subtraction in t_min[INT]. Long could */
+ /* be unable to represent -2147483648 on the host system. */
+ t_min[CHAR]=l2zm(-128L);
+ t_min[SHORT]=l2zm(-32768L);
+ t_min[INT]=t_min[SHORT];
+ t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
+ t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
+ t_min[MAXINT]=t_min(LLONG);
+ t_max[CHAR]=ul2zum(127L);
+ t_max[SHORT]=ul2zum(32767UL);
+ t_max[INT]=t_max[SHORT];
+ t_max[LONG]=ul2zum(2147483647UL);
+ t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
+ t_max[MAXINT]=t_max(LLONG);
+ tu_max[CHAR]=ul2zum(255UL);
+ tu_max[SHORT]=ul2zum(65535UL);
+ tu_max[INT]=tu_max[SHORT];
+ tu_max[LONG]=ul2zum(4294967295UL);
+ tu_max[LLONG]=zumkompl(ul2zum(0UL));
+ tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
+
+ return 1;
+}
+
+/* Returns the register in which variables of type typ are returned (or 0 if it
+ * can't be done). */
+
+int freturn(struct Typ *typ)
+{
+ int s = sizetab[typ->flags & NQ];
+ if ((typ->flags & NQ) == VOID)
+ return USERREG;
+ if ((s <= sizetab[INT]) && (s > 0))
+ return USERREG;
+ return 0;
+}
+
+/* Returns 1 if register reg can store variables of type typ. mode is set
+ * if the register is a pointer and the register is going to be dereferenced.
+ */
+
+int regok(int reg, int typf, int mode)
+{
+ int s = sizetab[typf & NQ];
+ if ((typf & NQ) == VOID)
+ return 1;
+ if ((s <= sizetab[INT]) && (s > 0))
+ return 1;
+ return 0;
+}
+
+/* Returns zero if the IC ic can be safely executed without danger of
+ * exceptions or similar things; for example, divisions or pointer dereferences
+ * are dangerous. This is used by the optimiser for code reordering.
+ */
+
+int dangerous_IC(struct IC *ic)
+{
+ /* Check for dereferences. */
+
+ if ((ic->q1.flags & DREFOBJ) ||
+ (ic->q2.flags & DREFOBJ) ||
+ (ic->z.flags & DREFOBJ))
+ return 0;
+
+ /* Division or modulo? */
+
+ if ((ic->code == DIV) ||
+ (ic->code == MOD))
+ return 0;
+
+ /* Safe, as far as we can tell. */
+
+ return 1;
+}
+
+/* Returns zero if the code for converting type p->ntyp to type typ is a noop.
+ */
+
+int must_convert(int otyp, int typ,int const_expr)
+{
+ int oldtype = otyp & NQ;
+ int newtype = typ & NQ;
+
+ /* ints and shorts are equivalent. */
+
+ if (oldtype == SHORT)
+ oldtype = INT;
+ if (newtype == SHORT)
+ newtype = INT;
+
+ /* Both the same type? */
+
+ if (oldtype == newtype)
+ return 0;
+
+#if 0
+ /* Converting two basic integers? */
+
+ if ((oldtype <= INT) && (newtype <= INT))
+ {
+ /* ... but char to short needs an AND. */
+
+ if ((oldtype == CHAR) && (newtype != CHAR))
+ return 1;
+ return 0;
+ }
+#endif
+
+ /* Pointer to/from int? */
+
+ if (((oldtype == INT) || (oldtype == POINTER)) &&
+ ((newtype == INT) || (newtype == POINTER)))
+ return 0;
+
+ /* Everything else needs code. */
+
+ return 1;
+}
+
+/* Ensure the output is aligned. A noop on the Z-machine. */
+
+void gen_align(FILE* fp, zmax align)
+{
+}
+
+/* Generate the label part of a variable definition. */
+
+void gen_var_head(FILE* fp, struct Var* var)
+{
+ if (var->storage_class == EXTERN)
+ debugemit(fp, "! Var %s %X\n", var->identifier, var->flags);
+ if (var->storage_class == STATIC)
+ debugemit(fp, "! Var static %ld %s %X\n", var->offset, var->identifier, var->flags);
+
+ /* We only want to emit records for genuinely defined variables. For
+ * some reason, TENTATIVE is defined for some of this. */
+
+ if ((var->storage_class == EXTERN) &&
+ !(var->flags & DEFINED) &&
+ !(var->flags & TENTATIVE))
+ return;
+
+ reflower(fp);
+ virgin = -1;
+ switch (var->storage_class)
+ {
+ case EXTERN:
+ /* This doesn't actually mean external linkage; it
+ * means a non-static global that may be referenced
+ * externally. */
+ fprintf(fp, "Array _%s ->\n",
+ var->identifier);
+ currentvar.type = EXTERN;
+ currentvar.val.identifier = strdup(var->identifier);
+ currentvar.offset = 0;
+ break;
+
+ case STATIC:
+ fprintf(fp, "Array STATIC_%s_%ld ->\n",
+ modulename, var->offset);
+ currentvar.type = STATIC;
+ currentvar.val.number = var->offset;
+ currentvar.offset = 0;
+ break;
+ }
+}
+
+/* Emit a certain number of bytes of bss data. No bss on the Z-machine,
+ * remember. */
+
+void gen_ds(FILE *fp, zmax size, struct Typ *typ)
+{
+ fprintf(fp, " %ld\n", size);
+ currentvar.offset += size;
+}
+
+/* Emit a certain number of bytes of initialised data. */
+
+void gen_dc(FILE *fp, int typf, struct const_list *p)
+{
+ switch (typf & NQ)
+ {
+ case CHAR:
+ fprintf(fp, " (%d)\n",
+ p->val.vuchar);
+ currentvar.offset += 1;
+ break;
+
+ case SHORT:
+ case INT:
+ reallyanint:
+ fprintf(fp, " (%d) (%d)\n",
+ xbyte(p->val.vint, 1),
+ xbyte(p->val.vint, 0));
+ currentvar.offset += 2;
+ break;
+
+ case LONG:
+ fprintf(fp, " (%d) (%d) (%d) (%d)\n",
+ xbyte(p->val.vlong, 3),
+ xbyte(p->val.vlong, 2),
+ xbyte(p->val.vlong, 1),
+ xbyte(p->val.vlong, 0));
+ currentvar.offset += 4;
+ break;
+
+ case POINTER:
+ if (!p->tree)
+ goto reallyanint;
+ {
+ struct fixup* fixup = malloc(sizeof(struct fixup));
+ struct obj* obj = &p->tree->o;
+ fixup->next = fixuplist;
+ fixuplist = fixup;
+ fixup->identifier = currentvar;
+
+ switch (obj->v->storage_class)
+ {
+ case EXTERN:
+ fixup->value.type = EXTERN;
+ fixup->value.val.identifier = strdup(obj->v->identifier);
+ break;
+
+ case STATIC:
+ fixup->value.type = STATIC;
+ fixup->value.val.number = obj->v->offset;
+ break;
+
+ default:
+ ierror(0);
+ }
+ fixup->value.offset = 0;
+ fixup->offset = obj->val.vlong;
+ fprintf(fp, " (0) (0)\n");
+ currentvar.offset += 2;
+ }
+ break;
+
+ default:
+ printf("type %d\n", typf);
+ ierror(0);
+ }
+}
+
+/* Returns the offset of the (STATIC or AUTO) given object. */
+
+zmax voff(struct obj* obj)
+{
+ zmax offset = obj->v->offset;
+ if (offset < 0)
+ offset = stackparamadjust + stackoffset - offset - maxalign;
+ else
+ offset += stackparamadjust;
+
+ offset += obj->val.vlong;
+ return offset;
+}
+
+/* When a varargs function is called, we need to find where the parameters are
+ * on the stack in order to make the __va_start magic variable work. This
+ * function does that. */
+
+static int find_varargs(void)
+{
+ int offset = 0;
+ struct reg_handle rh = empty_reg_handle;
+ struct struct_declaration* sd = function->vtyp->exact;
+ int stackalign;
+ int i;
+
+ for (i=0; i<sd->count; i++)
+ {
+ /* Ignore the parameter if it's been assigned a register. */
+
+ if ((*sd->sl)[i].reg != 0)
+ continue;
+
+ /* void shouldn't happen. */
+
+ if (((*sd->sl)[i].styp->flags & NQ) == VOID)
+ ierror(0);
+
+ /* Does the backend want to assign it to a register? */
+
+ if (reg_parm(&rh, (*sd->sl)[i].styp, 0, 0))
+ continue;
+
+ /* Add on the size of this parameter. */
+
+ offset += sizetab[(*sd->sl)[i].styp->flags & NQ];
+
+ /* Stack align. */
+
+ stackalign = align[(*sd->sl)[i].styp->flags & NQ];
+ offset = ((offset+1) / stackalign) * stackalign;
+ }
+
+ return (offset + stackoffset);
+}
+
+/* Output the name of a global. */
+
+static void emit_identifier(FILE* fp, struct obj* obj)
+{
+ switch (obj->v->storage_class)
+ {
+ case STATIC:
+ fprintf(fp, "STATIC_%s_%ld",
+ modulename, obj->v->offset);
+ break;
+
+ case EXTERN:
+ fprintf(fp, "_%s", obj->v->identifier);
+ break;
+
+ default:
+ ierror(0);
+ }
+}
+
+/* Save a register. */
+
+static void write_reg(FILE* fp, struct obj* obj, int typf, int reg)
+{
+ int flags = obj->flags &
+ (KONST|REG|VAR|DREFOBJ|VARADR);
+
+ /* Constant? */
+
+ if (flags == KONST)
+ ierror(0);
+
+ /* Dereference? */
+
+ if (flags & DREFOBJ)
+ goto dereference;
+
+ /* Register? */
+
+ if ((flags == REG) ||
+ ((flags & VAR) && (flags & REG) && (obj->v->storage_class == AUTO)) ||
+ ((flags & VAR) && (flags & REG) && (obj->v->storage_class == REGISTER)))
+ {
+ if (flags & DREFOBJ)
+ fprintf(fp, "\t@store%c %s 0 %s;\n",
+ ((typf & NQ) == CHAR) ? 'b' : 'w',
+ regnames[obj->reg], regnames[reg]);
+ else
+ {
+ struct zop in;
+ struct zop out;
+ in.type = ZOP_REG;
+ in.val.reg = reg;
+ out.type = ZOP_REG;
+ out.val.reg = obj->reg;
+ emit_add(fp, &in, &zop_zero, &out);
+ }
+#if 0
+ fprintf(fp, "\t@add %s 0 -> %s;\n",
+ regnames[reg], regnames[obj->reg]);
+#endif
+ return;
+ }
+
+ /* It must be a variable. */
+
+ switch (obj->v->storage_class)
+ {
+ case AUTO:
+ case REGISTER: /* Local variable */
+ {
+ zmax offset = voff(obj);
+
+ if ((typf & NQ) == CHAR)
+ fprintf(fp, "\t@storeb xp 0%+ld %s;\n",
+ offset, regnames[reg]);
+ else
+ {
+ if (offset & 1)
+ {
+ struct zop c;
+ c.type = ZOP_CONSTANT;
+ c.val.constant = offset;
+ emit_add(fp, &zop_xp, &c, &zop_stack);
+ //fprintf(fp, "\t@add xp 0%+ld -> sp;\n", offset);
+ fprintf(fp, "\t@storew sp 0 %s;\n", regnames[reg]);
+ }
+ else
+ fprintf(fp, "\t@storew xp 0%+ld %s;\n",
+ offset >> 1, regnames[reg]);
+ }
+ return;
+ }
+
+ case EXTERN:
+ case STATIC:
+
+ /* Dereference object. */
+
+ if ((typf & NQ) == CHAR)
+ {
+ fprintf(fp, "\t@storeb ");
+ emit_identifier(fp, obj);
+ fprintf(fp, " 0%+ld %s;\n",
+ obj->val.vlong, regnames[reg]);
+ }
+ else
+ {
+ if (obj->val.vlong & 1)
+ {
+ fprintf(fp, "\t@add ");
+ emit_identifier(fp, obj);
+ fprintf(fp, " 0%+ld -> sp;\n",
+ obj->val.vlong);
+ fprintf(fp, "\t@storew sp 0 %s;\n",
+ regnames[reg]);
+ }
+ else
+ {
+ fprintf(fp, "\t@storew ");
+ emit_identifier(fp, obj);
+ fprintf(fp, " 0%+ld %s;\n",
+ obj->val.vlong >> 1, regnames[reg]);
+ }
+ }
+ return;
+#if 0
+ case EXTERN: /* External linkage */
+ if ((typf & NQ) == CHAR)
+ fprintf(fp, "\t@storeb _%s 0%+ld %s;\n",
+ obj->v->identifier, offset, regnames[reg]);
+ else
+ {
+
+ fprintf(fp, "\t@storew _%s 0 %s;\n",
+ obj->v->identifier, regnames[reg]);
+ return;
+
+ case STATIC: /* Static global */
+ if ((typf & NQ) == CHAR)
+ fprintf(fp, "\t@storeb STATIC_%s_%ld 0%+ld %s;\n",
+ modulename, obj->v->offset, offset, regnames[reg]);
+ else
+ fprintf(fp, "\t@storew STATIC_%s_%ld 0 %s;\n",
+ modulename, obj->v->offset, regnames[reg]);
+ return;
+#endif
+
+ default:
+ ierror(0);
+ }
+
+ ierror(0); // Not reached
+dereference:
+ /* These are a *pain*.
+ *
+ * The first thing we need to do is to read the old contents of the
+ * memory cell, to work out the address we need to write to; and then
+ * do the write. Hurray for the Z-machine stack. */
+
+ obj->flags &= ~DREFOBJ;
+ read_reg(fp, obj, POINTER, 0);
+ fprintf(fp, "\t@store%c sp 0 %s;\n",
+ ((typf & NQ) == CHAR) ? 'b' : 'w',
+ regnames[reg]);
+}
+
+/* Move one register to another register. */
+
+static void move_reg(FILE* fp, int reg1, int reg2)
+{
+ struct zop r1;
+ struct zop r2;
+ r1.type = ZOP_REG;
+ r1.val.reg = reg1;
+ r2.type = ZOP_REG;
+ r2.val.reg = reg2;
+ emit_add(fp, &r1, &zop_zero, &r2);
+}
+/* Load a value into a zop. */
+
+static void read_reg(FILE* fp, struct obj* obj, int typf, int reg)
+{
+ int flags = obj->flags &
+ (KONST|REG|VAR|DREFOBJ|VARADR);
+
+ /* The only thing you can do with a function is to take the address of
+ * it. */
+
+ if ((typf & NQ) == FUNKT)
+ flags &= ~DREFOBJ & ~VARADR;
+
+ /* Is this a memory dereference? */
+
+ if (flags & DREFOBJ)
+ goto dereference;
+
+ /* Constant? */
+
+ if (flags == KONST)
+ {
+ struct zop c;
+ struct zop r;
+ c.type = ZOP_CONSTANT;
+ //fprintf(fp, "\t@add ");
+ switch (typf & NQ)
+ {
+ case CHAR: c.val.constant = obj->val.vchar; break;
+ case UNSIGNED|CHAR: c.val.constant = obj->val.vuchar; break;
+ case SHORT: c.val.constant = obj->val.vshort; break;
+ case UNSIGNED|SHORT: c.val.constant = obj->val.vushort; break;
+ case POINTER: ierror(0);
+ case INT: c.val.constant = obj->val.vint; break;
+ case UNSIGNED|INT: c.val.constant = obj->val.vuint; break;
+ default:
+ ierror(typf);
+ }
+ r.type = ZOP_REG;
+ r.val.reg = reg;
+ emit_add(fp, &c, &zop_zero, &r);
+ //fprintf(fp, " 0 -> %s;\n", regnames[reg]);
+ }
+ else if (flags == REG) /* Register? */
+ {
+ move_reg(fp, obj->reg, reg);
+ //fprintf(fp, "\t@add %s 0 -> %s;\n", regnames[obj->reg], regnames[reg]);
+ }
+ else if ((flags & REG) && ((typf & NQ) == FUNKT)) /* Function pointer? */
+ {
+ move_reg(fp, obj->reg, reg);
+ //fprintf(fp, "\t@add %s 0 -> %s;\n", regnames[obj->reg], regnames[reg]);
+ }
+ else
+ {
+ /* It must be a variable. */
+
+ switch (obj->v->storage_class)
+ {
+ case AUTO:
+ case REGISTER: /* Local variable */
+ if (flags & VARADR)
+ {
+ fprintf(fp, "\t@add xp 0%+ld -> %s;\n",
+ voff(obj), regnames[reg]);
+ }
+ else if (flags & REG)
+ {
+ move_reg(fp, obj->reg, reg);
+ //fprintf(fp, "\t@add %s 0 -> %s;\n",
+ // regnames[obj->reg], regnames[reg]);
+ }
+ else
+ {
+ zmax offset = voff(obj);
+
+ if ((typf & NQ) == CHAR)
+ fprintf(fp, "\t@loadb xp 0%+ld -> %s;\n",
+ offset, regnames[reg]);
+ else
+ {
+ if (offset & 1)
+ {
+ fprintf(fp, "\t@add xp 0%+ld -> sp;\n", offset);
+ fprintf(fp, "\t@loadw sp 0 -> %s;\n", regnames[reg]);
+ }
+ else
+ fprintf(fp, "\t@loadw xp 0%+ld -> %s;\n",
+ offset >> 1, regnames[reg]);
+ }
+ }
+ break;
+
+ case STATIC:
+ case EXTERN: /* Global variable. Implicit dereference,
+ with the offset in obj->val.vlong. */
+
+ /* ...but functions are never dereferenced. */
+
+ if ((flags & VARADR) ||
+ ((typf & NQ) == FUNKT))
+ {
+ /* Fetch address of object. */
+
+ fprintf(fp, "\t@add ");
+ emit_identifier(fp, obj);
+ fprintf(fp, " 0%+ld -> %s;\n",
+ obj->val.vlong, regnames[reg]);
+ }
+ else if (strcmp(obj->v->identifier, "__va_start") == 0)
+ {
+ fprintf(fp, "\t@add xp 0%+ld -> %s;\n",
+ find_varargs(), regnames[reg]);
+ }
+ else
+ {
+ /* Dereference object. */
+
+ if ((typf & NQ) == CHAR)
+ {
+ fprintf(fp, "\t@loadb ");
+ emit_identifier(fp, obj);
+ fprintf(fp, " 0%+ld -> %s;\n",
+ obj->val.vlong, regnames[reg]);
+ }
+ else
+ {
+ if (obj->val.vlong & 1)
+ {
+ fprintf(fp, "\t@add ");
+ emit_identifier(fp, obj);
+ fprintf(fp, " 0%+ld -> sp;\n",
+ obj->val.vlong);
+ fprintf(fp, "\t@loadw sp 0 -> %s;\n",
+ regnames[reg]);
+ }
+ else
+ {
+ fprintf(fp, "\t@loadw ");
+ emit_identifier(fp, obj);
+ fprintf(fp, " 0%+ld -> %s;\n",
+ obj->val.vlong >> 1, regnames[reg]);
+ }
+ }
+ }
+ break;
+
+ default:
+ ierror(obj->v->storage_class);
+ }
+ }
+ return;
+
+dereference:
+ /* Do we need to dereference the thing we just fetched? */
+
+ /* Fetch the value to dereference. */
+ obj->flags &= ~DREFOBJ;
+ read_reg(fp, obj, POINTER, 0);
+
+ if (flags & DREFOBJ)
+ {
+ switch (typf & NQ)
+ {
+ case CHAR:
+ fprintf(fp, "\t@loadb sp 0 -> %s;\n",
+ regnames[reg], regnames[reg]);
+ break;
+
+ case SHORT:
+ case INT:
+ case POINTER:
+ case FUNKT:
+ fprintf(fp, "\t@loadw sp 0 -> %s;\n",
+ regnames[reg], regnames[reg]);
+ break;
+
+ default:
+ ierror(typf & NQ);
+ }
+ }
+}
+
+/* Returns the zop to use for an input parameter, pushing that parameter onto
+ * the stack if necessary. */
+
+static void push_value(FILE* fp, struct obj* obj, int typf, struct zop* op)
+{
+ int flags = obj->flags &
+ (KONST|REG|VAR|DREFOBJ|VARADR);
+
+ if (flags == KONST)
+ {
+ op->type = ZOP_CONSTANT;
+ switch (typf & NU)
+ {
+ case CHAR: op->val.constant = obj->val.vchar; break;
+ case UNSIGNED|CHAR: op->val.constant = obj->val.vuchar; break;
+ case SHORT: op->val.constant = obj->val.vshort; break;
+ case UNSIGNED|SHORT: op->val.constant = obj->val.vushort; break;
+ case INT: op->val.constant = obj->val.vint; break;
+ case UNSIGNED|INT: op->val.constant = obj->val.vuint; break;
+ case POINTER: ierror(0);
+ default:
+ fprintf(fp, "XXX !!! bad konst type %X\n", typf);
+ }
+ return;
+ }
+
+ /* The only thing you can do with a function is to take the address of it. */
+
+ if ((typf & NQ) == FUNKT)
+ flags &= ~DREFOBJ & ~VARADR;
+
+ /* This is used by the long code. The longop functions can only operate
+ * on pointers to longs; so if we need to pass in a constant, we have
+ * to stash it on the stack and return a pointer. */
+
+ if (flags == (KONST|VARADR))
+ {
+ op->type = ZOP_CONSTANTADDR;
+ op->val.constant = addconstant(obj->val.vlong);
+ return;
+ }
+
+ if (flags == REG)
+ {
+ debugemit(fp, "! zop reg %d\n", obj->reg);
+ op->type = ZOP_REG;
+ op->val.reg = obj->reg;
+ return;
+ }
+
+ if ((flags == (VAR|REG)) &&
+ ((obj->v->storage_class == AUTO) ||
+ (obj->v->storage_class == REGISTER)))
+ {
+ debugemit(fp, "! zop var reg %d\n", obj->reg);
+ op->type = ZOP_REG;
+ op->val.reg = obj->reg;
+ return;
+ }
+
+ if ((flags == (VAR|VARADR)) &&
+ (obj->v->storage_class == EXTERN) &&
+ (obj->v->offset == 0))
+ {
+ debugemit(fp, "! zop varaddr extern %s\n", obj->v->identifier);
+ op->type = ZOP_EXTERN;
+ op->val.identifier = obj->v->identifier;
+ return;
+ }
+
+ if ((flags == (VAR|VARADR)) &&
+ (obj->v->storage_class == STATIC) &&
+ (obj->v->offset == 0))
+ {
+ debugemit(fp, "! zop varaddr static %ld\n", obj->v->offset);
+ op->type = ZOP_STATIC;
+ op->val.constant = obj->v->offset;
+ return;
+ }
+
+ if ((flags & VAR) &&
+ ((obj->v->vtyp->flags & NQ) == FUNKT))
+ {
+ if (obj->v->storage_class == EXTERN)
+ {
+ op->type = ZOP_EXTERN;
+ op->val.identifier = obj->v->identifier;
+ }
+ else
+ {
+ op->type = ZOP_STATIC;
+ op->val.constant = obj->v->offset;
+ }
+ return;
+ }
+
+ read_reg(fp, obj, typf, 0);
+ op->type = ZOP_STACK;
+}
+
+/* Same as push_value(), but returns a zop for the *address* of the object, not
+ * the object itself. Used a lot by the long code. */
+
+static void push_addrof(FILE* fp, struct obj* obj, int typf, struct zop* op)
+{
+ if (obj->flags & DREFOBJ)
+ obj->flags &= ~DREFOBJ;
+ else
+ obj->flags |= VARADR;
+ push_value(fp, obj, POINTER, op);
+}
+
+/* Returns the zop to use for an output parameter. Unlike push_value, this does
+ * not emit a pop; that must be done later, if the return parameter is zero. */
+
+static void pop_value(FILE* fp, struct obj* obj, int typf, struct zop* op)
+{
+ int flags = obj->flags &
+ (KONST|REG|VAR|DREFOBJ|VARADR);
+
+ /* We don't even *try* to handle dereferences here. */
+
+ if (flags & DREFOBJ)
+ goto stack;
+
+ if (flags == REG)
+ goto reg;
+
+ if ((flags == (VAR|REG)) &&
+ ((obj->v->storage_class == AUTO) ||
+ (obj->v->storage_class == REGISTER)))
+ goto reg;
+
+stack:
+ op->type = ZOP_STACK;
+ return;
+
+reg:
+ op->type = ZOP_REG;
+ op->val.reg = obj->reg;
+}
+
+/* Writes code for a zop. */
+
+static void emit_zop(FILE* fp, struct zop* op)
+{
+ switch (op->type)
+ {
+ case ZOP_STACK:
+ fprintf(fp, "sp");
+ return;
+
+ case ZOP_REG:
+ fprintf(fp, "%s", regnames[op->val.reg]);
+ return;
+
+ case ZOP_CONSTANT:
+ fprintf(fp, "0%+ld", (zshort)op->val.constant);
+ return;
+
+ case ZOP_EXTERN:
+ fprintf(fp, "_%s", op->val.identifier);
+ return;
+
+ case ZOP_STATIC:
+ fprintf(fp, "STATIC_%s_%ld",
+ modulename, op->val.constant);
+ return;
+
+ case ZOP_CONSTANTADDR:
+ fprintf(fp, "CONSTANT_%s_%ld",
+ modulename, op->val.constant);
+ return;
+
+ default:
+ ierror(op->type);
+ }
+}
+
+/* This is used in conjunction with pop_value(). pop_value() returns a zop that
+ * represents the return value for a function. If that return value is the
+ * stack, the value on the stack needs to be written back into memory. That's
+ * what this function does. */
+
+static void fin_zop(FILE* fp, struct obj* obj, int typf, struct zop* op)
+{
+ switch (op->type)
+ {
+ case ZOP_STACK:
+ write_reg(fp, obj, typf, 0);
+ return;
+
+ case ZOP_REG:
+ return;
+
+ default:
+ ierror(0);
+ }
+}
+
+/* Emit a basic ADD instruction.
+ * This routine tests for all the various special cases, of which there are
+ * many, and attempts to produce optimal code.
+ */
+
+static void emit_add(FILE* fp, struct zop* q1, struct zop* q2, struct zop* z)
+{
+ /* Sometimes we get ZOP_REG with reg=0. This actually means the stack. */
+
+ if ((q1->type == ZOP_REG) && (q1->val.reg == 0))
+ q1 = &zop_stack;
+ if ((q2->type == ZOP_REG) && (q2->val.reg == 0))
+ q2 = &zop_stack;
+ if ((z->type == ZOP_REG) && (z->val.reg == 0))
+ z = &zop_stack;
+
+ /* If q2 is a constant and 0, then this might be a register move of
+ * some kind. */
+
+ if ((q2->type == ZOP_CONSTANT) && (q2->val.constant == 0))
+ {
+ /* Left is a register? */
+ if (q1->type == ZOP_REG)
+ {
+ /* Right is a register? */
+ if (z->type == ZOP_REG)
+ {
+ /* They're the *same* register? */
+ if (q1->val.reg == z->val.reg)
+ {
+ /* No code need be emitted. */
+ return;
+ }
+
+ /* Emit a @store instruction. Unfortunately, I
+ * can't work out the syntax for Inform's
+ * @store opcode, so we emit a high-level
+ * assignment instead and let Inform work it
+ * out. */
+
+ fprintf(fp, "\t");
+ emit_zop(fp, z);
+ fprintf(fp, " = ");
+ emit_zop(fp, q1);
+ fprintf(fp, ";\n");
+ return;
+ }
+
+ /* Right is the stack? */
+ if (z->type == ZOP_STACK)
+ {
+ /* We're pushing the single parameter onto the
+ * stack. */
+
+ fprintf(fp, "\t@push ");
+ emit_zop(fp, q1);
+ fprintf(fp, ";\n");
+ return;
+ }
+ }
+
+ /* Left is the stack? */
+ if (q1->type == ZOP_STACK)
+ {
+ /* Right is a register? */
+ if (z->type == ZOP_REG)
+ {
+ /* We're popping the single parameter off the
+ * stack. */
+
+ fprintf(fp, "\t@pull ");
+ emit_zop(fp, z);
+ fprintf(fp, ";\n");
+ return;
+ }
+ }
+ }
+
+ /* Fall back on an ordinary @add. */
+
+ fprintf(fp, "\t@add ");
+ emit_zop(fp, q1);
+ fprintf(fp, " ");
+ emit_zop(fp, q2);
+ fprintf(fp, " -> ");
+ emit_zop(fp, z);
+ fprintf(fp, ";\n");
+}
+
+/* Copy a value from one zop to another. This is not quite as simple as you
+ * might think, because there are a number of optimisation cases to take into
+ * account.
+ *
+ * NOTE: for simplicity, this function will never emit just a single
+ * instruction --- the assignment is always done via the stack. FIXME. */
+
+static void move_value(FILE* fp, struct obj* q1o, struct obj* zo, int typf)
+{
+ struct zop q1;
+ struct zop z;
+
+ pop_value(fp, zo, typf, &z);
+ push_value(fp, q1o, typf, &q1);
+ debugemit(fp, "! L=%d R=%d\n", q1.type, z.type);
+ /* In all cases except when push_value() and fin_zop() *both* emit
+ * code, we need to insert an assignment here. As they only emit code
+ * in the ZOP_STACK case... */
+ if ((q1.type != ZOP_STACK) || (z.type != ZOP_STACK))
+ {
+ emit_add(fp, &q1, &zop_zero, &z);
+#if 0
+ fprintf(fp, "\t@add ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " 0 -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+#endif
+ }
+ fin_zop(fp, zo, typf, &z);
+}
+
+/* Copy a 32-bit value from one obj to another. */
+
+static void move_long_value(FILE* fp, struct obj* q1, struct obj* z, int typf)
+{
+ int flags = q1->flags &
+ (KONST|REG|VAR|DREFOBJ|VARADR);
+ struct zop q1z;
+ struct zop zz;
+
+ if (flags == KONST)
+ {
+ int hi = xword(q1->val.vlong, 1);
+ int lo = xword(q1->val.vlong, 0);
+
+ push_addrof(fp, z, POINTER, &zz);
+ fprintf(fp, "\t@call_vn __long_loadconst ");
+ emit_zop(fp, &zz);
+ fprintf(fp, " 0%+ld 0%+ld;\n", (short)hi, (short)lo);
+ return;
+ }
+
+ push_addrof(fp, z, POINTER, &zz);
+ push_addrof(fp, q1, POINTER, &q1z);
+ fprintf(fp, "\t@copy_table ");
+ emit_zop(fp, &q1z);
+ fprintf(fp, " ");
+ emit_zop(fp, &zz);
+ fprintf(fp, " 4;\n");
+}
+
+/* The code generator itself.
+ * This big, complicated, hairy and scary function does the work to actually
+ * produce the code. fp is the output stream, ic the beginning of the ic
+ * chain, func is a pointer to the actual function and stackframe is the size
+ * of the function's stack frame.
+ */
+
+void gen_code(FILE* fp, struct IC *ic, struct Var* func, zmax stackframe)
+{
+ int i;
+ struct zop q1;
+ struct zop q2;
+ struct zop z;
+ int code, typf; // ...of the IC under consideration
+
+ int c,t,lastcomp=0,reg;
+
+ function = func;
+
+ /* r0..r5 are always used for parameter passing. */
+
+ regused[2] = 1;
+ regused[3] = 1;
+ regused[4] = 1;
+ regused[5] = 1;
+ regused[6] = 1;
+ regused[7] = 1;
+
+ /* This is the offset of the stack frame, relative to the current stack
+ * pointer. */
+
+ stackoffset = stackframe;
+
+ /* No parameters pushed yet. */
+
+ stackparamadjust = 0;
+
+ reflower(fp);
+
+ if (func->storage_class == STATIC)
+ fprintf(fp, "[ STATIC_%s_%ld xp\n", modulename, func->offset);
+ else
+ fprintf(fp, "[ _%s xp\n", func->identifier);
+
+ /* Tell Inform what registers the function is using. */
+
+ for (i=1; i<=MAXR; i++)
+ {
+ //fprintf(fp, "! i=%d used %d scratch %d alloc %d\n",
+ // i, regused[i], regscratch[i], regsa[i]);
+ if (regused[i] && !regsa[i])
+ fprintf(fp, "\t%s\n", regnames[i]);
+ }
+ fprintf(fp, ";\n");
+
+ /* Trace the function name. */
+
+ if (g_flags[1] & USEDFLAG)
+ {
+ if (func->storage_class == STATIC)
+ fprintf(fp, "print \"STATIC_%s_%ld^\";\n", modulename, func->offset);
+ else
+ fprintf(fp, "print \"_%s^\";\n", func->identifier);
+ }
+
+ /* Adjust stack for locals. */
+
+ if (stackframe)
+ fprintf(fp, "\t@sub xp 0%+ld -> xp;\n", stackframe);
+ //if (stackoffset)
+ // fprintf(fp, "\txp = xp - %ld\n", stackframe);
+
+
+ /* Iterate through all ICs. */
+
+ for (; dump_ic(fp, ic), ic; ic=ic->next)
+ {
+ c=ic->code;t=ic->typf;
+ code = ic->code;
+ typf = ic->typf;
+
+ /* Do nothing for NOPs. */
+
+ if (code == NOP)
+ continue;
+
+ /* Has the stack been adjusted due to a call? */
+
+#if 0
+ if (stackcalladjustment)
+ {
+ if ((code != GETRETURN) &&
+ (code != FREEREG) &&
+ (code != ALLOCREG))
+ {
+ debugemit(fp, "! stack reset %d %d\n",
+ stackparamadjust, stackcallparamsize);
+ fprintf(fp, "\t@add xp %d -> xp;\n",
+ stackparamadjust+stackcallparamsize);
+ stackparamadjust = 0;
+ stackcallparamsize = 0;
+ stackcalladjustment = 0;
+ }
+ }
+#endif
+
+#if 0
+ if(notpopped&&!dontpop){
+ int flag=0;
+ if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
+ fprintf(fp,"\tadd\t%s,#%ld\n",regnames[sp],notpopped);
+ stackoffset+=notpopped;notpopped=0;
+ }
+ }
+#endif
+ /* These opcodes turn into other opcodes. */
+
+ switch (code)
+ {
+ case SUBPFP:
+ case SUBIFP:
+ code = SUB;
+ break;
+
+ case ADDI2P:
+ code = ADD;
+ break;
+ }
+
+ /* And now the big opcode switch. */
+
+ switch (code)
+ {
+ case ALLOCREG: /* Mark register in use */
+ regs[ic->q1.reg] = 1;
+ continue;
+
+ case FREEREG: /* Mark register not in use */
+ regs[ic->q1.reg] = 0;
+ continue;
+
+ case LABEL: /* Emit jump target */
+ fprintf(fp, ".%s%d;\n",
+ labelprefix, typf);
+ continue;
+
+ case BRA: /* Unconditional jump */
+ fprintf(fp, "\tjump %s%d;\n",
+ labelprefix, typf);
+ continue;
+
+ case GETRETURN: /* Read the last function call's return parameter */
+ switch (typf & NQ)
+ {
+ case CHAR:
+ //if (ic->q2.val.vlong != 1)
+ // goto copy_struct;
+ /* fall through */
+ case SHORT:
+ case INT:
+ case POINTER:
+ write_reg(fp, &ic->z, typf, 2);
+ break;
+
+ /* Ignore the following; the
+ * front-end will automatically
+ * pass in an implicit
+ * parameter to the function
+ * containing the address of
+ * the return parameter, so
+ * GETRETURN ought to be a
+ * noop. */
+ case LONG:
+ case STRUCT:
+ case VOID:
+ case ARRAY:
+ break;
+#if 0
+ copy_struct:
+ push_addrof(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@copy_table xp ");
+ emit_zop(fp, &z);
+ fprintf(fp, " %ld;\n", szof(ic->z.v->vtyp));
+ break;
+#endif
+
+ default:
+ ierror(typf & NQ);
+ }
+ //fprintf(fp, "\tr0 = ");
+ //emit_object(fp, &ic->q1, typf);
+ //fprintf(fp, ";\n");
+ //write_reg(fp, &ic->z, typf, 2);
+ continue;
+
+ case SETRETURN: /* Set this function's return parameter */
+ switch (typf & NQ)
+ {
+ case CHAR:
+ //if (ic->q2.val.vlong != 1)
+ // goto setreturn_copy_struct;
+
+ /* fall through */
+ case SHORT:
+ case INT:
+ case POINTER:
+ read_reg(fp, &ic->q1, typf, 2);
+ break;
+
+ case LONG:
+ case STRUCT:
+ case VOID:
+ case ARRAY:
+#if 0
+ setreturn_copy_struct:
+ fprintf(fp, "\t@add xp %ld -> sp;\n",
+ stackoffset);
+ push_addrof(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@copy_table ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " sp %ld;\n", szof(ic->q1.v->vtyp));
+ break;
+#endif
+
+ default:
+ ierror(typf & NQ);
+ }
+ //fprintf(fp, "\tr0 = ");
+ //emit_object(fp, &ic->q1, typf);
+ //fprintf(fp, ";\n");
+ continue;
+
+ case MINUS: /* Unary minus */
+ switch (typf & NQ)
+ {
+ case CHAR:
+ case SHORT:
+ case INT:
+ push_value(fp, &ic->q1, typf, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@sub 0 ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ fin_zop(fp, &ic->z, typf, &z);
+ break;
+
+ case LONG:
+ push_addrof(fp, &ic->z, typf, &z);
+ push_addrof(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@call_vn __long_neg ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ break;
+
+ default:
+ ierror(0);
+ }
+ continue;
+
+ case KOMPLEMENT: /* Unary komplement */
+ /* INFORM BUG! */
+ /* The @not opcode doesn't work. We have to use a
+ * wrapper function instead. */
+
+ push_value(fp, &ic->q1, typf, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@call_2s __not ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ fin_zop(fp, &ic->z, typf, &z);
+ continue;
+
+ case MOVEFROMREG: /* Write a register to memory */
+ write_reg(fp, &ic->z, typf, ic->q1.reg);
+ continue;
+
+ case MOVETOREG: /* Read a register from memory */
+ read_reg(fp, &ic->q1, typf, ic->z.reg);
+ continue;
+
+ case ASSIGN: /* Move something to somewhere else */
+ debugemit(fp, "! ASSIGN size %d typf %d\n", ic->q2.val.vlong, typf & NQ);
+ switch (typf & NQ)
+ {
+ case CHAR:
+ if (ic->q2.val.vlong != 1)
+ goto assign_copy_struct;
+ /* fall through */
+ case SHORT:
+ case INT:
+ case POINTER:
+ move_value(fp, &ic->q1, &ic->z, typf);
+ break;
+
+ case LONG:
+ move_long_value(fp, &ic->q1, &ic->z, typf);
+ break;
+
+ case STRUCT:
+ case VOID:
+ case ARRAY:
+ assign_copy_struct:
+ push_addrof(fp, &ic->z, typf, &z);
+ push_addrof(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@copy_table ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " ");
+ emit_zop(fp, &z);
+ fprintf(fp, " 0%+ld;\n", ic->q2.val.vlong);
+ break;
+
+ default:
+ ierror(typf & NQ);
+ }
+ continue;
+
+ case ADDRESS: /* Fetch the address of something, always
+ AUTO or STATIC */
+ i = voff(&ic->q1);
+ pop_value(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@add xp 0%+ld -> ", i);
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ fin_zop(fp, &ic->z, typf, &z);
+ continue;
+
+ case PUSH: /* Push a value onto the stack */
+ fprintf(fp, "\t@sub xp 0%+ld -> xp;\n",
+ ic->q2.val.vlong);
+ //stackoffset += ic->q2.val.vlong;
+ stackparamadjust += ic->q2.val.vlong;
+
+ switch (ic->q2.val.vlong)
+ {
+ case 1:
+ push_value(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@storeb xp 0 ");
+ emit_zop(fp, &q1);
+ fprintf(fp, ";\n");
+ break;
+
+ case 2:
+ push_value(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@storew xp 0 ");
+ emit_zop(fp, &q1);
+ fprintf(fp, ";\n");
+ break;
+
+ default:
+ push_addrof(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@copy_table ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " xp 0%+ld;\n", ic->q2.val.vlong);
+ break;
+ }
+ continue;
+
+ case ADD: /* Add two numbers */
+ case SUB: /* Subtract two numbers */
+ case MULT: /* Multiply two numbers */
+ case DIV: /* Divide two numbers */
+ case MOD: /* Modulo two numbers */
+ case OR: /* Bitwise or */
+ case XOR: /* Bitwise xor */
+ case AND: /* Bitwise and */
+ case LSHIFT: /* Shift left */
+ case RSHIFT: /* Shift right */
+ switch (typf & NQ)
+ {
+ case CHAR:
+ case SHORT:
+ case INT:
+ case POINTER:
+ /* Second parameter first! */
+ push_value(fp, &ic->q2, typf, &q2);
+
+ if (code == RSHIFT)
+ {
+ fprintf(fp, "\t@sub 0 ");
+ emit_zop(fp, &q2);
+ fprintf(fp, " -> sp;\n");
+ q2.type = ZOP_STACK;
+ }
+
+ push_value(fp, &ic->q1, typf, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ //fprintf(fp, "\t");
+ //emit_object(fp, &ic->z, typf);
+ //fprintf(fp, " = ");
+ //emit_object(fp, &ic->q1, typf);
+ switch (code)
+ {
+ case ADD:
+ fprintf(fp, "\t@add ");
+ break;
+
+ case SUB:
+ fprintf(fp, "\t@sub ");
+ break;
+
+ case MULT:
+ fprintf(fp, "\t@mul ");
+ break;
+
+ case DIV:
+ if (typf & UNSIGNED)
+ fprintf(fp, "\t@call_vs __unsigned_div ");
+ else
+ fprintf(fp, "\t@div ");
+ break;
+
+ case MOD:
+ if (typf & UNSIGNED)
+ fprintf(fp, "\t@call_vs __unsigned_mod ");
+ else
+ fprintf(fp, "\t@mod ");
+ break;
+
+ case AND:
+ fprintf(fp, "\t@and ");
+ break;
+
+ case XOR:
+ fprintf(fp, "\t@call_vs __xor ");
+ break;
+
+ case OR:
+ fprintf(fp, "\t@or ");
+ break;
+
+ case LSHIFT:
+ case RSHIFT:
+ if (typf & UNSIGNED)
+ fprintf(fp, "\t@log_shift ");
+ else
+ fprintf(fp, "\t@art_shift ");
+ break;
+
+ default:
+ /* Should never get here! */
+ ierror(0);
+ }
+ emit_zop(fp, &q1);
+ fprintf(fp, " ");
+ emit_zop(fp, &q2);
+ fprintf(fp, " -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ fin_zop(fp, &ic->z, typf, &z);
+ //emit_object(fp, &ic->q2, typf);
+ break;
+
+ case LONG:
+ /* Destination parameter first! */
+
+ push_addrof(fp, &ic->z, typf, &z);
+ push_addrof(fp, &ic->q2, typf, &q2);
+ push_addrof(fp, &ic->q1, typf, &q1);
+
+ fprintf(fp, "\t@call_vn __long_");
+ switch (code)
+ {
+ case ADD:
+ fprintf(fp, "add");
+ break;
+
+ case SUB:
+ fprintf(fp, "sub");
+ break;
+
+ case MULT:
+ fprintf(fp, "mul");
+ break;
+
+ case DIV:
+ if (typf & UNSIGNED)
+ fprintf(fp, "unsigned_div");
+ else
+ fprintf(fp, "div");
+ break;
+
+ case MOD:
+ if (typf & UNSIGNED)
+ fprintf(fp, "unsigned_mod");
+ else
+ fprintf(fp, "mod");
+ break;
+
+ case AND:
+ fprintf(fp, "and");
+ break;
+
+ case XOR:
+ fprintf(fp, "xor");
+ break;
+
+ case OR:
+ fprintf(fp, "or");
+ break;
+
+ case LSHIFT:
+ fprintf(fp, "lsl");
+ break;
+
+ case RSHIFT:
+ if (typf & UNSIGNED)
+ fprintf(fp, "lsr");
+ else
+ fprintf(fp, "asr");
+ break;
+
+ default:
+ /* Should never get here! */
+ ierror(0);
+ }
+ fprintf(fp, " ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " ");
+ emit_zop(fp, &q2);
+ fprintf(fp, " ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ break;
+
+ default:
+ ierror(0);
+ }
+ continue;
+
+ case CONVERT:
+ if((q1typ(ic)&NU)==CHAR){
+ switch (ztyp(ic) & NU)
+ {
+ case CHAR:
+ case UNSIGNED|CHAR:
+ case UNSIGNED|SHORT:
+ case UNSIGNED|INT:
+ case SHORT:
+ case INT:
+ push_value(fp, &ic->q1, CHAR, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@log_shift ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " 8 -> sp;\n");
+ fprintf(fp, "\t@art_shift sp 0-8 -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ fin_zop(fp, &ic->z, typf, &z);
+ break;
+
+ case LONG:
+ push_value(fp, &ic->q1, INT, &q1);
+ push_addrof(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@call_vn __long_fromchar");
+ emit_zop(fp, &z);
+ fprintf(fp, " ");
+ emit_zop(fp, &q1);
+ fprintf(fp, ";\n");
+ break;
+
+ default:
+ ierror(0);
+ }
+ continue;
+ }
+ if((q1typ(ic)&NU)==(UNSIGNED|CHAR)){
+
+ switch (ztyp(ic) & NQ)
+ {
+ case CHAR:
+ case SHORT:
+ case INT:
+ push_value(fp, &ic->q1, UNSIGNED|CHAR, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ if ((z.type != ZOP_STACK) || (q1.type != ZOP_STACK))
+ {
+ emit_add(fp, &q1, &zop_zero, &z);
+#if 0
+ fprintf(fp, "\t@add ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " 0 -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+#endif
+ }
+ fin_zop(fp, &ic->z, typf, &z);
+ break;
+
+ case LONG:
+ push_value(fp, &ic->q1, UNSIGNED|CHAR, &q1);
+ push_addrof(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@call_vn __long_fromint");
+ emit_zop(fp, &z);
+ fprintf(fp, " 0 ");
+ emit_zop(fp, &q1);
+ fprintf(fp, ";\n");
+ break;
+
+ default:
+ ierror(0);
+ }
+ continue;
+ }
+ if((q1typ(ic)&NU)==SHORT||(q1typ(ic)&NU)==INT){
+ switch (ztyp(ic) & NU)
+ {
+ case CHAR:
+ case UNSIGNED|CHAR:
+ case UNSIGNED|SHORT:
+ case UNSIGNED|INT:
+ case SHORT:
+ case INT:
+ push_value(fp, &ic->q1, INT, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ if ((z.type != ZOP_STACK) || (q1.type != ZOP_STACK))
+ {
+ emit_add(fp, &q1, &zop_zero, &z);
+#if 0
+ fprintf(fp, "\t@add ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " 0 -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+#endif
+ }
+ fin_zop(fp, &ic->z, typf, &z);
+ break;
+
+ case LONG:
+ push_value(fp, &ic->q1, INT, &q1);
+ push_addrof(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@call_vn __long_fromint ");
+ emit_zop(fp, &z);
+ fprintf(fp, " ");
+ emit_zop(fp, &q1);
+ fprintf(fp, ";\n");
+ break;
+
+ case UNSIGNED|LONG:
+ push_value(fp, &ic->q1, INT, &q1);
+ push_addrof(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@call_vn __long_loadconst ");
+ emit_zop(fp, &z);
+ fprintf(fp, " 0 ");
+ emit_zop(fp, &q1);
+ fprintf(fp, ";\n");
+ break;
+
+ default:
+ ierror(typf);
+ }
+ continue;
+ }
+ if((q1typ(ic)&NU)==(UNSIGNED|SHORT)||(q1typ(ic)&NU)==(UNSIGNED|INT)||(q1typ(ic)&NU)==POINTER){
+
+ switch (ztyp(ic) & NQ)
+ {
+ case CHAR:
+ case SHORT:
+ case INT:
+ push_value(fp, &ic->q1, INT, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ if ((z.type != ZOP_STACK) || (q1.type != ZOP_STACK))
+ {
+ emit_add(fp, &q1, &zop_zero, &z);
+#if 0
+ fprintf(fp, "\t@add ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " 0 -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+#endif
+ }
+ fin_zop(fp, &ic->z, typf, &z);
+ break;
+
+ case LONG:
+ push_value(fp, &ic->q1, INT, &q1);
+ push_addrof(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@call_vn __long_loadconst ");
+ emit_zop(fp, &z);
+ fprintf(fp, " 0 ");
+ emit_zop(fp, &q1);
+ fprintf(fp, ";\n");
+ break;
+#if 0
+ case SHORT:
+ case INT:
+ fprintf(fp, "\t");
+ emit_object(fp, &ic->z, typf);
+ fprintf(fp, " = (");
+ emit_object(fp, &ic->q1, CHAR);
+ fprintf(fp, ") << 8 >> 8;\n");
+ break;
+#endif
+
+ default:
+ printf("%X\n", typf);
+ ierror(0);
+ }
+ continue;
+ }
+ if((q1typ(ic)&NU)==(UNSIGNED|LONG)||(q1typ(ic)&NU)==LONG){
+
+ switch (ztyp(ic) & NQ)
+ {
+ case CHAR:
+ push_addrof(fp, &ic->q1, LONG, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@loadb ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " 3 -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ fin_zop(fp, &ic->z, typf, &z);
+ break;
+
+ case SHORT:
+ case INT:
+ push_addrof(fp, &ic->q1, LONG, &q1);
+ pop_value(fp, &ic->z, typf, &z);
+ fprintf(fp, "\t@loadw ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " 1 -> ");
+ emit_zop(fp, &z);
+ fprintf(fp, ";\n");
+ fin_zop(fp, &ic->z, typf, &z);
+ break;
+
+ default:
+ ierror(typf & NQ);
+ }
+ continue;
+ }
+ case COMPARE:
+ /* COMPARE is special. The next instruction is
+ * always a branch. The Z-machine does
+ * branches in the form:
+ *
+ * @j{e,g,l} <var1> <var2> [~]@<label>
+ *
+ * However, we don't know what short of branch
+ * to emit until the next instruction (which is
+ * the IC for a branch). So we have to stash
+ * the zops that we're using for the
+ * compare here, for use later. This is done
+
+ * using the globals compare1 and compare2.
+ */
+
+ switch (typf & NU)
+ {
+ case CHAR:
+ case SHORT:
+ case INT:
+ case POINTER:
+ /* Second parameter first! */
+ push_value(fp, &ic->q2, typf, &compare2);
+ push_value(fp, &ic->q1, typf, &compare1);
+ break;
+
+ case UNSIGNED|CHAR:
+ case UNSIGNED|SHORT:
+ case UNSIGNED|INT:
+ /* Because the Z-machine only
+ * has signed comparisons, we
+ * need a dodgy algorithm to
+ * do this, which works as
+ * follows: in the signed
+ * domain, 0-7FFF compares
+ * greater than 8000-FFFF. In
+ * the unsigned domain, it's
+ * the other way around. So,
+ * by flipping the sign bits
+ * we do the logical
+ * equivalent of shifting the
+ * unsigned range up/down by
+ * 8000 which makes it fit
+ * the signed range. There.
+ * Did you understand that?
+ * Neither did I, the first
+ * few times it was explained
+ * to me. */
+ read_reg(fp, &ic->q2, typf, 0);
+ fprintf(fp, "\t@add sp $8000 -> sp;\n");
+ read_reg(fp, &ic->q1, typf, 0);
+ fprintf(fp, "\t@add sp $8000 -> sp;\n");
+ compare1.type = ZOP_STACK;
+ compare2.type = ZOP_STACK;
+ break;
+
+ case LONG:
+ push_addrof(fp, &ic->q2, typf, &q2);
+ push_addrof(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@call_vs __long_compare ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " ");
+ emit_zop(fp, &q2);
+ fprintf(fp, " -> sp;\n");
+ compare1.type = ZOP_STACK;
+ compare2.type = ZOP_CONSTANT;
+ compare2.val.constant = 0;
+ break;
+
+ case UNSIGNED|LONG:
+ push_addrof(fp, &ic->q2, typf, &q2);
+ push_addrof(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@call_vs __long_unsigned_compare ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " ");
+ emit_zop(fp, &q2);
+ fprintf(fp, " -> sp;\n");
+ compare1.type = ZOP_STACK;
+ compare2.type = ZOP_CONSTANT;
+ compare2.val.constant = 0;
+ break;
+
+ default:
+ ierror(typf & NQ);
+ }
+ continue;
+
+ case TEST:
+ /* TEST is a special COMPARE. It takes one
+ * parameter and always tests it against 0; it
+ * is guaranteed to be followed by BNE or BEQ.
+ * */
+
+ switch (typf & NQ)
+ {
+ case CHAR:
+ case SHORT:
+ case INT:
+ case POINTER:
+ push_value(fp, &ic->q1, typf, &compare1);
+ compare2.type = ZOP_CONSTANT;
+ compare2.val.constant = 0;
+ break;
+
+ case LONG:
+ push_addrof(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@call_vs __long_compare ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " ");
+ q2.type = ZOP_CONSTANTADDR;
+ q2.val.constant = addconstant(0);
+ emit_zop(fp, &q2);
+ fprintf(fp, " -> sp;\n", i);
+ compare1.type = ZOP_STACK;
+ compare2.type = ZOP_CONSTANT;
+ compare2.val.constant = 0;
+ break;
+
+ default:
+ ierror(typf & NQ);
+ }
+ continue;
+
+ case BEQ:
+ case BNE:
+ case BLT:
+ case BGE:
+ case BLE:
+ case BGT:
+ {
+ static int branchlabel = 0;
+
+ fprintf(fp, "\t@j");
+ switch (code)
+ {
+ case BNE:
+ case BEQ: fprintf(fp, "e "); break;
+ case BLT:
+ case BGE: fprintf(fp, "l "); break;
+ case BGT:
+ case BLE: fprintf(fp, "g "); break;
+ }
+
+ emit_zop(fp, &compare1);
+ fprintf(fp, " ");
+ emit_zop(fp, &compare2);
+ fprintf(fp, " ?");
+
+ if (g_flags[3] & USEDFLAG)
+ {
+ if (!((code == BNE) || (code == BGE) || (code == BLE)))
+ fprintf(fp, "~");
+ fprintf(fp, "LL%d;\n", branchlabel);
+ fprintf(fp, "\tjump %s%d;\n", labelprefix, typf);
+ fprintf(fp, ".LL%d;\n", branchlabel++);
+ }
+ else
+ {
+ if ((code == BNE) || (code == BGE) || (code == BLE))
+ fprintf(fp, "~");
+ fprintf(fp, "%s%d;\n", labelprefix, typf);
+ }
+ continue;
+ }
+
+ case CALL:
+ {
+#if 0
+ /* Calculate the amount of stack to reserve for
+ * the return parameter. ints and smaller go in
+ * the return register. */
+
+ stackcallparamsize = szof(ic->q1.v->vtyp->next);
+ if (stackcallparamsize <= sizetab[INT])
+ stackcallparamsize = 0;
+
+ if (stackcallparamsize)
+ fprintf(fp, "\t@sub xp %d -> xp;\n",
+ stackcallparamsize);
+#endif
+
+ /* Is this actually an inline assembly function? */
+
+ if ((ic->q1.flags & VAR) &&
+ ic->q1.v->fi &&
+ ic->q1.v->fi->inline_asm)
+ {
+ /* Yes. Emit the assembly code. */
+
+ fprintf(fp, "%s", ic->q1.v->fi->inline_asm);
+ }
+ else
+ {
+ /* No; so emit a call. */
+
+ push_value(fp, &ic->q1, typf, &q1);
+ fprintf(fp, "\t@call_vs2 ");
+ emit_zop(fp, &q1);
+ fprintf(fp, " xp r0 r1 r2 r3 r4 r5 -> r0;\n");
+ }
+
+ //stackcalladjustment = 1;
+
+ /* If any parameters have been pushed, adjust
+ * the stack to pop them. */
+
+ if (stackparamadjust)
+ {
+ fprintf(fp, "\t@add xp 0%+ld -> xp;\n",
+ stackparamadjust);
+ //stackoffset -= stackparamadjust;
+ stackparamadjust = 0;
+ }
+ continue;
+ }
+
+ default:
+ ierror(code);
+ }
+
+ }
+
+ /* We really ought to tidy the stack up; but there's no need, because
+ * the old value of xp will be restored when the function exits. */
+
+ //if (stackframe)
+ // fprintf(fp, "\t@add xp %ld -> xp;\n", stackframe);
+
+ fprintf(fp, "\t@ret r0;\n");
+ fprintf(fp, "]\n");
+
+// function_bottom(fp, func, loff);
+}
+
+int shortcut(int code, int typ)
+{
+ return(0);
+}
+
+// Add a constant to the constant pool.
+
+static int addconstant(zmax value)
+{
+ struct constant* c;
+
+ /* Check to see if the constant's already in the pool. */
+
+ c = constantlist;
+ while (c)
+ {
+ if (c->value == value)
+ return c->id;
+ c = c->next;
+ }
+
+ /* It's not; add it. */
+
+ c = malloc(sizeof(struct constant));
+ c->next = constantlist;
+ c->id = constantnum++;
+ c->value = value;
+ constantlist = c;
+ return c->id;
+}
+
+void cleanup_cg(FILE *fp)
+{
+ struct fixup* fixup = fixuplist;
+
+ /* Have we actually emitted anything? */
+
+ if (!fp)
+ return;
+
+ reflower(fp);
+
+ /* Emit the constant pool. */
+
+ {
+ struct constant* constant = constantlist;
+
+ while (constant)
+ {
+ fprintf(fp, "Array CONSTANT_%s_%ld -->\n",
+ modulename, constant->id);
+ fprintf(fp, " 0%+ld 0%+ld;\n",
+ xword(constant->value, 1),
+ xword(constant->value, 0));
+ constant = constant->next;
+ }
+ }
+
+ /* Emit the code to initialise the data area. */
+
+ {
+ struct fixup* fixup = fixuplist;
+
+ fprintf(fp, "[ __init_vars_%s;\n", modulename);
+ while (fixup)
+ {
+ fprintf(fp, "\t@add 0%+ld ", fixup->offset);
+
+ switch (fixup->value.type)
+ {
+ case STATIC:
+ fprintf(fp, "STATIC_%s_%ld -> sp;\n",
+ modulename, fixup->value.val.number);
+ break;
+
+ case EXTERN:
+ fprintf(fp, "_%s -> sp;\n",
+ fixup->value.val.identifier);
+ break;
+
+ default:
+ ierror(0);
+ }
+
+ switch (fixup->identifier.type)
+ {
+ case STATIC:
+ fprintf(fp, "\t@storew STATIC_%s_%ld 0%+ld sp;\n",
+ modulename, fixup->identifier.val.number,
+ fixup->identifier.offset);
+ break;
+
+ case EXTERN:
+ fprintf(fp, "\t@storew _%s 0%+ld sp;\n",
+ fixup->identifier.val.identifier,
+ fixup->identifier.offset);
+ break;
+
+ default:
+ ierror(0);
+ }
+
+ fixup = fixup->next;
+ }
+ fprintf(fp, "];\n");
+ }
+}
+
+/* The code generator's asking us to pass a parameter in a register. */
+
+int reg_parm(struct reg_handle *rh, struct Typ *typ, int vararg, struct Typ *ft)
+{
+ /* Vararg parameters never go in registers. */
+
+ if (vararg)
+ return 0;
+
+ /* Will the parameter fit? */
+
+ if (sizetab[typ->flags & NQ] > 2)
+ return 0;
+
+ /* Still enough registers? */
+
+ if (rh->reg >= NUM_REGPARMS+USERREG)
+ return 0;
+
+ return (rh->reg++);
+}
+
+int reg_pair(int r,struct rpair *p)
+/* Returns 0 if the register is no register pair. If r */
+/* is a register pair non-zero will be returned and the */
+/* structure pointed to p will be filled with the two */
+/* elements. */
+{
+ return 0;
+}
+void init_db(FILE *f)
+{
+}
+void cleanup_db(FILE *f)
+{
+}
diff --git a/machines/z/machine.dt b/machines/z/machine.dt
new file mode 100755
index 0000000..41828bc
--- /dev/null
+++ b/machines/z/machine.dt
@@ -0,0 +1,14 @@
+S8BS
+S8BU
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S16BSLE S16BSBE
+S16BULE S16BUBE
+S32BSLE S32BSBE
+S32BULE S32BUBE
+S64BSLE S64BSBE
+S64BULE S64BUBE
+S32BIEEEBE S32BIEEELE
+S64BIEEEBE S64BIEEELE
+S64BIEEEBE S64BIEEELE
+S16BULE S16BUBE
diff --git a/machines/z/machine.h b/machines/z/machine.h
new file mode 100755
index 0000000..6f43fc8
--- /dev/null
+++ b/machines/z/machine.h
@@ -0,0 +1,81 @@
+/* Z-machine code generator
+ * David Given
+ */
+
+#include "dt.h"
+
+/* Machine specific addressing-modes. Not used. */
+
+struct AddressingMode{
+ int never_used;
+};
+
+/* The number of registers we support. We don't really have any, but we
+ * use local variables instead; we have 14.
+ */
+
+#define MAXR 14
+
+/* Number of command-line options we accept. */
+
+#define MAXGF 6
+
+/* If this is set to zero vbcc will not generate ICs where the target operand
+ * is the same as the 2nd source operand. This can sometimes simplify the
+ * code-generator, but usually the code is better if the code-generator allows
+ * it.
+ */
+
+#define USEQ2ASZ 1
+
+/* The smallest and largest integer type that can be added to a pointer. */
+
+#define MINADDI2P INT
+#define MAXADDI2P INT
+
+/* Big-endian? */
+
+#define BIGENDIAN 1
+
+/* Little-endian? */
+
+#define LITTLEENDIAN 0
+
+/* If switch-statements should be generated as a sequence of SUB,TST,BEQ ICs
+ * rather than COMPARE,BEQ ICs set this to 1. This can yield better code on
+ * some machines.
+ */
+
+#define SWITCHSUBS 0
+
+/* In optimizing compilation certain library memcpy/strcpy-calls with length
+ * known at compile-time will be inlined using an ASSIGN-IC if the size is less
+ * or equal to INLINEMEMCPY. The type used for the ASSIGN-IC will be
+ * UNSIGNED|CHAR. On the Z-machine, memcpy can be done in `hardware' with the
+ * @copy_table opcode, so always inline them if possible.
+ */
+
+#define INLINEMEMCPY 65536
+
+/* Do we want to pass parameters to functions in registers? */
+
+#define HAVE_REGPARMS 1
+
+/* If so, how many? Max 7 due to the architecture, but one is always xp. */
+
+#define NUM_REGPARMS 6
+
+/* This structure is used to keep track of where register parameters go. */
+
+struct reg_handle {
+ int reg;
+};
+
+/* Do we want to use zuint for size_t rather than the default zulong? */
+
+#define HAVE_INT_SIZET 1
+
+/* size of buffer for asm-output */
+#define EMIT_BUF_LEN 1024 /* should be enough */
+/* number of asm-output lines buffered */
+#define EMIT_BUF_DEPTH 4